Skip to content

Commit

Permalink
bugfix: fix the sql exception when pk is str (apache#4653)
Browse files Browse the repository at this point in the history
  • Loading branch information
caohdgege authored Jul 8, 2022
1 parent 41382b4 commit 708f97f
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
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;
Expand Down Expand Up @@ -122,8 +125,7 @@ protected void prepareUndoLogAll(TableRecords beforeImage, TableRecords afterIma
return;
}
ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();
TableRecords lockKeyRecords = afterImage;
String lockKeys = buildLockKey(lockKeyRecords);
String lockKeys = buildLockKey(afterImage);
connectionProxy.appendLockKey(lockKeys);
buildUndoItemAll(connectionProxy, beforeImage, afterImage);
}
Expand Down Expand Up @@ -201,7 +203,8 @@ protected SQLUndoLog buildUndoItem(SQLType sqlType, TableRecords beforeImage, Ta

@Override
protected TableRecords afterImage(TableRecords beforeImage) throws SQLException {
TableMeta tmeta = getTableMeta();
TableMeta tableMeta = getTableMeta();

List<Row> rows = beforeImage.getRows();
Map<String, ArrayList<Object>> primaryValueMap = new HashMap<>();
rows.forEach(m -> {
Expand All @@ -212,49 +215,59 @@ protected TableRecords afterImage(TableRecords beforeImage) throws SQLException
});
});

// The origin select sql contains the unique keys sql
StringBuilder afterImageSql = new StringBuilder(selectSQL);
List<Object> primaryValues = new ArrayList<>();

// Appends the pk when the origin select sql not contains
for (int i = 0; i < rows.size(); i++) {
int finalI = i;
List<String> wherePrimaryList = new ArrayList<>();
primaryValueMap.forEach((k, v) -> {
wherePrimaryList.add(k + " = " + primaryValueMap.get(k).get(finalI) + " ");
wherePrimaryList.add(k + " = ? ");
primaryValues.add(v);
});
afterImageSql.append(" OR (").append(Joiner.on(" and ").join(wherePrimaryList)).append(") ");
}
return buildTableRecords2(tmeta, afterImageSql.toString(), paramAppenderList);

return buildTableRecords2(tableMeta, afterImageSql.toString(), paramAppenderList, primaryValues);
}

@Override
public TableRecords beforeImage() throws SQLException {
TableMeta tmeta = getTableMeta();
//after image sql the same of before image
TableMeta tableMeta = getTableMeta();
// After image sql the same of before image
if (StringUtils.isBlank(selectSQL)) {
paramAppenderList = new ArrayList<>();
selectSQL = buildImageSQL(tmeta);
selectSQL = buildImageSQL(tableMeta);
}
return buildTableRecords2(tmeta, selectSQL, paramAppenderList);
return buildTableRecords2(tableMeta, selectSQL, paramAppenderList, Collections.emptyList());
}

/**
* build TableRecords
*
* @param tableMeta
* @param selectSQL
* @param paramAppenderList
* @param tableMeta the meta info of table
* @param selectSQL the sql to select images
* @param paramAppenderList the param list
* @param primaryKeys the primary keys
* @return the table records
* @throws SQLException
* @throws SQLException then execute fail
*/
public TableRecords buildTableRecords2(TableMeta tableMeta, String selectSQL, ArrayList<List<Object>> paramAppenderList) 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")) {
if (CollectionUtils.isNotEmpty(paramAppenderList)) {
for (int i = 0, ts = paramAppenderList.size(); i < ts; i++) {
List<Object> paramAppender = paramAppenderList.get(i);
for (int j = 0, ds = paramAppender.size(); j < ds; j++) {
ps.setObject(i * ds + j + 1, "NULL".equals(paramAppender.get(j).toString()) ? null : paramAppender.get(j));
}
int ts = CollectionUtils.isEmpty(paramAppenderList) ? 0 : paramAppenderList.size();
int ds = ts == 0 ? 0 : paramAppenderList.get(0).size();
for (int i = 0; i < ts; i++) {
List<Object> paramAppender = paramAppenderList.get(i);
for (int j = 0; j < ds; j++) {
ps.setObject(i * ds + j + 1, "NULL".equals(paramAppender.get(j).toString()) ? null : paramAppender.get(j));
}
}
for (int i = 0; i < primaryKeys.size(); i++) {
ps.setObject(ts * ds + i + 1, primaryKeys.get(i));
}

rs = ps.executeQuery();
return TableRecords.buildRecords(tableMeta, rs);
} finally {
Expand All @@ -265,7 +278,7 @@ public TableRecords buildTableRecords2(TableMeta tableMeta, String selectSQL, Ar
/**
* build image sql
*
* @param tableMeta
* @param tableMeta the meta info of table
* @return image sql
*/
public String buildImageSQL(TableMeta tableMeta) {
Expand All @@ -274,8 +287,8 @@ public String buildImageSQL(TableMeta tableMeta) {
}
SQLInsertRecognizer recognizer = (SQLInsertRecognizer) sqlRecognizer;
int insertNum = recognizer.getInsertParamsValue().size();
Map<String, ArrayList<Object>> imageParamperterMap = buildImageParamperters(recognizer);
StringBuilder prefix = new StringBuilder("SELECT * ");
Map<String, ArrayList<Object>> imageParameterMap = buildImageParameters(recognizer);
String prefix = "SELECT * ";
StringBuilder suffix = new StringBuilder(" FROM ").append(getFromTableInSQL());
boolean[] isContainWhere = {false};
for (int i = 0; i < insertNum; i++) {
Expand All @@ -287,12 +300,12 @@ public String buildImageSQL(TableMeta tableMeta) {
List<String> uniqueList = new ArrayList<>();
for (ColumnMeta m : v.getValues()) {
String columnName = m.getColumnName();
if (imageParamperterMap.get(columnName) == null && m.getColumnDef() != null) {
if (imageParameterMap.get(columnName) == null && m.getColumnDef() != null) {
uniqueList.add(columnName + " = DEFAULT(" + columnName + ") ");
columnIsNull = false;
continue;
}
if ((imageParamperterMap.get(columnName) == null && m.getColumnDef() == null) || imageParamperterMap.get(columnName).get(finalI) == null || imageParamperterMap.get(columnName).get(finalI) instanceof Null) {
if ((imageParameterMap.get(columnName) == null && m.getColumnDef() == null) || imageParameterMap.get(columnName).get(finalI) == null || imageParameterMap.get(columnName).get(finalI) instanceof Null) {
if (!"PRIMARY".equalsIgnoreCase(k)) {
columnIsNull = false;
uniqueList.add(columnName + " is ? ");
Expand All @@ -303,7 +316,7 @@ public String buildImageSQL(TableMeta tableMeta) {
}
columnIsNull = false;
uniqueList.add(columnName + " = ? ");
paramAppenderTempList.add(imageParamperterMap.get(columnName).get(finalI));
paramAppenderTempList.add(imageParameterMap.get(columnName).get(finalI));
}
if (!columnIsNull) {
if (isContainWhere[0]) {
Expand All @@ -317,31 +330,31 @@ public String buildImageSQL(TableMeta tableMeta) {
});
paramAppenderList.add(paramAppenderTempList);
}
StringJoiner selectSQLJoin = new StringJoiner(", ", prefix.toString(), suffix.toString());
StringJoiner selectSQLJoin = new StringJoiner(", ", prefix, suffix.toString());
return selectSQLJoin.toString();
}

/**
* build sql params
*
* @param recognizer
* @param recognizer the sql recognizer
* @return map, key is column, value is paramperter
*/
@SuppressWarnings("lgtm[java/dereferenced-value-may-be-null]")
public Map<String, ArrayList<Object>> buildImageParamperters(SQLInsertRecognizer recognizer) {
List<String> duplicateKeyUpdateCloms = recognizer.getDuplicateKeyUpdate();
if (CollectionUtils.isNotEmpty(duplicateKeyUpdateCloms)) {
public Map<String, ArrayList<Object>> buildImageParameters(SQLInsertRecognizer recognizer) {
List<String> duplicateKeyUpdateColumns = recognizer.getDuplicateKeyUpdate();
if (CollectionUtils.isNotEmpty(duplicateKeyUpdateColumns)) {
getTableMeta().getAllIndexes().forEach((k, v) -> {
if ("PRIMARY".equalsIgnoreCase(k)) {
for (ColumnMeta m : v.getValues()) {
if (duplicateKeyUpdateCloms.contains(m.getColumnName())) {
if (duplicateKeyUpdateColumns.contains(m.getColumnName())) {
throw new ShouldNeverHappenException("update pk value is not supported!");
}
}
}
});
}
Map<String, ArrayList<Object>> imageParamperterMap = new HashMap<>();
Map<String, ArrayList<Object>> imageParameterMap = new HashMap<>();
Map<Integer, ArrayList<Object>> parameters = ((PreparedStatementProxy) statementProxy).getParameters();
// VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
List<String> insertParamsList = recognizer.getInsertParamsValue();
Expand All @@ -352,13 +365,13 @@ public Map<String, ArrayList<Object>> buildImageParamperters(SQLInsertRecognizer
for (int i = 0; i < insertColumns.size(); i++) {
String m = insertColumns.get(i);
String params = insertParamsArray[i];
ArrayList<Object> imageListTemp = imageParamperterMap.computeIfAbsent(m, k -> new ArrayList<>());
ArrayList<Object> imageListTemp = imageParameterMap.computeIfAbsent(m, k -> new ArrayList<>());
if ("?".equals(params.trim())) {
ArrayList<Object> objects = parameters.get(paramsindex);
imageListTemp.addAll(objects);
paramsindex++;
} else if (params instanceof String) {
// params is characterstring constant
// 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);
Expand All @@ -367,10 +380,10 @@ public Map<String, ArrayList<Object>> buildImageParamperters(SQLInsertRecognizer
} else {
imageListTemp.add(params);
}
imageParamperterMap.put(m, imageListTemp);
imageParameterMap.put(m, imageListTemp);
}
}
return imageParamperterMap;
return imageParameterMap;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Collections;

import com.google.common.collect.Lists;
import io.seata.rm.datasource.ConnectionProxy;
Expand Down Expand Up @@ -87,34 +88,34 @@ public void init() {
}

@Test
public void TestBuildImageParamperters(){
public void TestBuildImageParameters(){
mockParameters();
List<String> insertParamsList = new ArrayList<>();
insertParamsList.add("?,?,?,?");
insertParamsList.add("?,?,?,?");
when(sqlInsertRecognizer.getInsertParamsValue()).thenReturn(insertParamsList);
mockInsertColumns();
Map<String, ArrayList<Object>> imageParamperterMap = insertOrUpdateExecutor.buildImageParamperters(sqlInsertRecognizer);
Assertions.assertEquals(imageParamperterMap.toString(),mockImageParamperterMap().toString());
Map<String, ArrayList<Object>> imageParameterMap = insertOrUpdateExecutor.buildImageParameters(sqlInsertRecognizer);
Assertions.assertEquals(imageParameterMap.toString(),mockImageParameterMap().toString());
}

@Test
public void TestBuildImageParamperters_contain_constant(){
mockImageParamperterMap_contain_constant();
public void TestBuildImageParameters_contain_constant(){
mockImageParameterMap_contain_constant();
List<String> insertParamsList = new ArrayList<>();
insertParamsList.add("?,?,?,userStatus1");
insertParamsList.add("?,?,?,userStatus2");
when(sqlInsertRecognizer.getInsertParamsValue()).thenReturn(insertParamsList);
mockInsertColumns();
Map<String, ArrayList<Object>> imageParamperterMap = insertOrUpdateExecutor.buildImageParamperters(sqlInsertRecognizer);
Assertions.assertEquals(imageParamperterMap.toString(),mockImageParamperterMap().toString());
Map<String, ArrayList<Object>> imageParameterMap = insertOrUpdateExecutor.buildImageParameters(sqlInsertRecognizer);
Assertions.assertEquals(imageParameterMap.toString(),mockImageParameterMap().toString());
}

@Test
public void testBuildImageSQL(){
String selectSQLStr = "SELECT * FROM null WHERE (user_id = ? ) OR (id = ? ) OR (user_id = ? ) OR (id = ? ) ";
String paramAppenderListStr = "[[userId1, 100], [userId2, 101]]";
mockImageParamperterMap_contain_constant();
mockImageParameterMap_contain_constant();
List<String> insertParamsList = new ArrayList<>();
insertParamsList.add("?,?,?,userStatus1");
insertParamsList.add("?,?,?,userStatus2");
Expand All @@ -128,7 +129,7 @@ public void testBuildImageSQL(){

@Test
public void testBeforeImage(){
mockImageParamperterMap_contain_constant();
mockImageParameterMap_contain_constant();
List<String> insertParamsList = new ArrayList<>();
insertParamsList.add("?,?,?,userStatus1");
insertParamsList.add("?,?,?,userStatus2");
Expand All @@ -140,7 +141,7 @@ public void testBeforeImage(){
TableRecords tableRecords = new TableRecords();
String selectSQL = insertOrUpdateExecutor.buildImageSQL(tableMeta);
ArrayList<List<Object>> paramAppenderList = insertOrUpdateExecutor.getParamAppenderList();
doReturn(tableRecords).when(insertOrUpdateExecutor).buildTableRecords2(tableMeta,selectSQL,paramAppenderList);
doReturn(tableRecords).when(insertOrUpdateExecutor).buildTableRecords2(tableMeta,selectSQL,paramAppenderList, Collections.emptyList());
TableRecords tableRecordsResult = insertOrUpdateExecutor.beforeImage();
Assertions.assertEquals(tableRecords,tableRecordsResult);
} catch (SQLException throwables) {
Expand Down Expand Up @@ -216,7 +217,7 @@ private void mockParameters() {
* exist insert parms is constant
* {1=[100], 2=[userId1], 3=[userName1], 4=[101], 5=[userId2], 6=[userName2]}
*/
private void mockImageParamperterMap_contain_constant() {
private void mockImageParameterMap_contain_constant() {
Map<Integer,ArrayList<Object>> paramters = new HashMap<>(4);
ArrayList arrayList10 = new ArrayList<>();
arrayList10.add(PK_VALUE);
Expand All @@ -240,25 +241,25 @@ private void mockImageParamperterMap_contain_constant() {
when(psp.getParameters()).thenReturn(paramters);
}

private Map<String, ArrayList<Object>> mockImageParamperterMap(){
Map<String, ArrayList<Object>> imageParamperterMap = new HashMap<>();
private Map<String, ArrayList<Object>> mockImageParameterMap(){
Map<String, ArrayList<Object>> imageParameterMap = new HashMap<>();
ArrayList<Object> idList = new ArrayList<>();
idList.add("100");
idList.add("101");
imageParamperterMap.put("id",idList);
imageParameterMap.put("id",idList);
ArrayList<Object> user_idList = new ArrayList<>();
user_idList.add("userId1");
user_idList.add("userId2");
imageParamperterMap.put("user_id",user_idList);
imageParameterMap.put("user_id",user_idList);
ArrayList<Object> user_nameList = new ArrayList<>();
user_nameList.add("userName1");
user_nameList.add("userName2");
imageParamperterMap.put("user_name",user_nameList);
imageParameterMap.put("user_name",user_nameList);
ArrayList<Object> user_statusList = new ArrayList<>();
user_statusList.add("userStatus1");
user_statusList.add("userStatus2");
imageParamperterMap.put("user_status",user_statusList);
return imageParamperterMap;
imageParameterMap.put("user_status",user_statusList);
return imageParameterMap;
}

private void mockParametersOfOnePk() {
Expand Down

0 comments on commit 708f97f

Please sign in to comment.