diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/AbstractDMLBaseExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/AbstractDMLBaseExecutor.java index f522d8d6e59dcc4da638fac4654693b1a26ea78a..ab7383206d6aad5321c3c7f527df3d882890523a 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/AbstractDMLBaseExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/AbstractDMLBaseExecutor.java @@ -20,6 +20,7 @@ import java.sql.Statement; import java.util.List; import java.util.concurrent.Callable; import io.seata.common.exception.NotSupportYetException; +import io.seata.common.exception.ShouldNeverHappenException; import io.seata.rm.datasource.AbstractConnectionProxy; import io.seata.rm.datasource.ConnectionContext; import io.seata.rm.datasource.ConnectionProxy; @@ -27,6 +28,7 @@ import io.seata.rm.datasource.StatementProxy; import io.seata.rm.datasource.sql.struct.TableRecords; import io.seata.sqlparser.SQLRecognizer; import io.seata.sqlparser.util.JdbcConstants; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,7 +63,7 @@ public abstract class AbstractDMLBaseExecutor<T, S extends Statement> extends Ba * * @param statementProxy the statement proxy * @param statementCallback the statement callback - * @param sqlRecognizers the multi sql recognizer + * @param sqlRecognizers the multi sql recognizer */ public AbstractDMLBaseExecutor(StatementProxy<S> statementProxy, StatementCallback<T, S> statementCallback, List<SQLRecognizer> sqlRecognizers) { @@ -86,8 +88,7 @@ public abstract class AbstractDMLBaseExecutor<T, S extends Statement> extends Ba * @throws Exception the exception */ protected T executeAutoCommitFalse(Object[] args) throws Exception { - if (!JdbcConstants.MYSQL.equalsIgnoreCase(getDbType()) && getTableMeta().getPrimaryKeyOnlyName().size() > 1) - { + if (!JdbcConstants.MYSQL.equalsIgnoreCase(getDbType()) && getTableMeta().getPrimaryKeyOnlyName().size() > 1) { throw new NotSupportYetException("multi pk only support mysql!"); } TableRecords beforeImage = beforeImage(); @@ -172,4 +173,13 @@ public abstract class AbstractDMLBaseExecutor<T, S extends Statement> extends Ba return LOCK_RETRY_POLICY_BRANCH_ROLLBACK_ON_CONFLICT; } } + + protected void assertContainsPKColumnName(List<String> updateColumns) { + for (String columnName : updateColumns) { + String standardColumnName = getStandardPkColumnName(columnName); + if (StringUtils.isNotEmpty(standardColumnName)) { + throw new ShouldNeverHappenException("Sorry, update pk value is not supported!"); + } + } + } } diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseInsertExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseInsertExecutor.java index 4b5c77b17f11fe32ad09d1e779398a34d3b528cd..8090a63848381605987b2ac7734d804a81114ad4 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseInsertExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseInsertExecutor.java @@ -73,7 +73,7 @@ public abstract class BaseInsertExecutor<T, S extends Statement> extends Abstrac @Override protected TableRecords afterImage(TableRecords beforeImage) throws SQLException { - Map<String,List<Object>> pkValues = getPkValues(); + Map<String, List<Object>> pkValues = getPkValues(); TableRecords afterImage = buildTableRecords(pkValues); if (afterImage == null) { throw new SQLException("Failed to build after-image for insert"); @@ -102,8 +102,8 @@ public abstract class BaseInsertExecutor<T, S extends Statement> extends Abstrac * get pk index * @return the key is pk column name and the value is index of the pk column */ - protected Map<String,Integer> getPkIndex() { - Map<String,Integer> pkIndexMap = new HashMap<>(); + protected Map<String, Integer> getPkIndex() { + Map<String, Integer> pkIndexMap = new HashMap<>(); SQLInsertRecognizer recognizer = (SQLInsertRecognizer) sqlRecognizer; List<String> insertColumns = recognizer.getInsertColumns(); if (CollectionUtils.isNotEmpty(insertColumns)) { @@ -111,7 +111,7 @@ public abstract class BaseInsertExecutor<T, S extends Statement> extends Abstrac for (int paramIdx = 0; paramIdx < insertColumnsSize; paramIdx++) { String sqlColumnName = insertColumns.get(paramIdx); if (containPK(sqlColumnName)) { - pkIndexMap.put(getStandardColumnName(sqlColumnName),paramIdx); + pkIndexMap.put(getStandardPkColumnName(sqlColumnName), paramIdx); } } return pkIndexMap; @@ -121,7 +121,7 @@ public abstract class BaseInsertExecutor<T, S extends Statement> extends Abstrac for (Map.Entry<String, ColumnMeta> entry : allColumns.entrySet()) { pkIndex++; if (containPK(entry.getValue().getColumnName())) { - pkIndexMap.put(ColumnUtils.delEscape(entry.getValue().getColumnName(),getDbType()),pkIndex); + pkIndexMap.put(ColumnUtils.delEscape(entry.getValue().getColumnName(), getDbType()), pkIndex); } } return pkIndexMap; @@ -132,21 +132,21 @@ public abstract class BaseInsertExecutor<T, S extends Statement> extends Abstrac * parse primary key value from statement. * @return */ - protected Map<String,List<Object>> parsePkValuesFromStatement() { + protected Map<String, List<Object>> parsePkValuesFromStatement() { // insert values including PK SQLInsertRecognizer recognizer = (SQLInsertRecognizer) sqlRecognizer; final Map<String, Integer> pkIndexMap = getPkIndex(); if (pkIndexMap.isEmpty()) { throw new ShouldNeverHappenException("pkIndex is not found"); } - Map<String,List<Object>> pkValuesMap = new HashMap<>(); + Map<String, List<Object>> pkValuesMap = new HashMap<>(); boolean ps = true; if (statementProxy instanceof PreparedStatementProxy) { PreparedStatementProxy preparedStatementProxy = (PreparedStatementProxy) statementProxy; List<List<Object>> insertRows = recognizer.getInsertRows(pkIndexMap.values()); if (insertRows != null && !insertRows.isEmpty()) { - Map<Integer,ArrayList<Object>> parameters = preparedStatementProxy.getParameters(); + Map<Integer, ArrayList<Object>> parameters = preparedStatementProxy.getParameters(); final int rowSize = insertRows.size(); int totalPlaceholderNum = -1; for (List<Object> row : insertRows) { @@ -276,19 +276,16 @@ public abstract class BaseInsertExecutor<T, S extends Statement> extends Abstrac * @param pkValues * @return */ - protected boolean checkPkValuesForMultiPk(Map<String,List<Object>> pkValues) { + protected boolean checkPkValuesForMultiPk(Map<String, List<Object>> pkValues) { Set<String> pkNames = pkValues.keySet(); - if (pkNames.isEmpty()) - { + if (pkNames.isEmpty()) { throw new ShouldNeverHappenException(); } int rowSize = pkValues.get(pkNames.iterator().next()).size(); - for (int i = 0;i < rowSize; i++) - { + for (int i = 0; i < rowSize; i++) { int n = 0; int m = 0; - for (String name : pkNames) - { + for (String name : pkNames) { Object pkValue = pkValues.get(name).get(i); if (pkValue instanceof Null) { n++; @@ -297,24 +294,21 @@ public abstract class BaseInsertExecutor<T, S extends Statement> extends Abstrac m++; } } - if (n > 1) - { + if (n > 1) { return false; } - if (m > 0) - { + if (m > 0) { return false; } } return true; } - protected boolean checkPkValues(Map<String,List<Object>> pkValues, boolean ps) { + protected boolean checkPkValues(Map<String, List<Object>> pkValues, boolean ps) { Set<String> pkNames = pkValues.keySet(); if (pkNames.size() == 1) { - return checkPkValuesForSinglePk(pkValues.get(pkNames.iterator().next()),ps); - } - else { + return checkPkValuesForSinglePk(pkValues.get(pkNames.iterator().next()), ps); + } else { return checkPkValuesForMultiPk(pkValues); } } @@ -322,7 +316,7 @@ public abstract class BaseInsertExecutor<T, S extends Statement> extends Abstrac /** * check pk values for single pk * @param pkValues - * @param ps true: is prepared statement. false: normal statement. + * @param ps true: is prepared statement. false: normal statement. * @return true: support. false: not support. */ protected boolean checkPkValuesForSinglePk(List<Object> pkValues, boolean ps) { diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java index 18ec187f3330c1f3b0c3868a9739643722d44007..ef22dd584f97ba2ab3dc67912b6fb3d996d109ed 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java @@ -244,11 +244,11 @@ public abstract class BaseTransactionalExecutor<T, S extends Statement> implemen /** - * get standard column name from user sql column name + * get standard pk column name from user sql column name * * @return */ - protected String getStandardColumnName(String userColumnName) { + protected String getStandardPkColumnName(String userColumnName) { String newUserColumnName = ColumnUtils.delEscape(userColumnName, getDbType()); for (String cn : getTableMeta().getPrimaryKeyOnlyName()) { if (cn.toUpperCase().equals(newUserColumnName.toUpperCase())) { diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java index edde47b28bfacdc5b29602651735910f12b29a66..9ecd1eab0e94e2bee939dbeb2e46cc1134131274 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java @@ -80,6 +80,7 @@ public class MultiUpdateExecutor<T, S extends Statement> extends AbstractDMLBase sqlRecognizer = recognizer; SQLUpdateRecognizer sqlUpdateRecognizer = (SQLUpdateRecognizer) recognizer; List<String> updateColumns = sqlUpdateRecognizer.getUpdateColumns(); + assertContainsPKColumnName(updateColumns); updateColumnsSet.addAll(updateColumns); if (noWhereCondition) { continue; @@ -132,7 +133,7 @@ public class MultiUpdateExecutor<T, S extends Statement> extends AbstractDMLBase String selectSQL = buildAfterImageSQL(tmeta, beforeImage); ResultSet rs = null; try (PreparedStatement pst = statementProxy.getConnection().prepareStatement(selectSQL);) { - SqlGenerateUtils.setParamForPk(beforeImage.pkRows(),getTableMeta().getPrimaryKeyOnlyName(),pst); + SqlGenerateUtils.setParamForPk(beforeImage.pkRows(), getTableMeta().getPrimaryKeyOnlyName(), pst); rs = pst.executeQuery(); return TableRecords.buildRecords(tmeta, rs); } finally { @@ -149,7 +150,7 @@ public class MultiUpdateExecutor<T, S extends Statement> extends AbstractDMLBase updateColumnsSet.addAll(sqlUpdateRecognizer.getUpdateColumns()); } StringBuilder prefix = new StringBuilder("SELECT "); - String suffix = " FROM " + getFromTableInSQL() + " WHERE " + SqlGenerateUtils.buildWhereConditionByPKs(tableMeta.getPrimaryKeyOnlyName(),beforeImage.pkRows().size(),getDbType()); + String suffix = " FROM " + getFromTableInSQL() + " WHERE " + SqlGenerateUtils.buildWhereConditionByPKs(tableMeta.getPrimaryKeyOnlyName(), beforeImage.pkRows().size(), getDbType()); StringJoiner selectSQLJoiner = new StringJoiner(", ", prefix.toString(), suffix); if (ONLY_CARE_UPDATE_COLUMNS) { if (!containsPK(new ArrayList<>(updateColumnsSet))) { 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 c05c9484b7ee9cfba107880f7ce9939b0e2793ed..b899aa74e5de3f5b7b48d1ce82b8b5fe2d71bdf3 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 @@ -73,6 +73,8 @@ public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecu private String buildBeforeImageSQL(TableMeta tableMeta, ArrayList<List<Object>> paramAppenderList) { SQLUpdateRecognizer recognizer = (SQLUpdateRecognizer) sqlRecognizer; + List<String> updateColumns = recognizer.getUpdateColumns(); + assertContainsPKColumnName(updateColumns); StringBuilder prefix = new StringBuilder("SELECT "); StringBuilder suffix = new StringBuilder(" FROM ").append(getFromTableInSQL()); String whereCondition = buildWhereCondition(recognizer, paramAppenderList); @@ -90,7 +92,6 @@ public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecu suffix.append(" FOR UPDATE"); StringJoiner selectSQLJoin = new StringJoiner(", ", prefix.toString(), suffix.toString()); if (ONLY_CARE_UPDATE_COLUMNS) { - List<String> updateColumns = recognizer.getUpdateColumns(); if (!containsPK(updateColumns)) { selectSQLJoin.add(getColumnNamesInSQL(tableMeta.getEscapePkNameList(getDbType()))); }