This is an automated email from the ASF dual-hosted git repository. jianbin pushed a commit to branch 2.x in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push: new fa6bdda3c3 bugfix: the failure of rollbacking back of the delete SQL at AT mode when using SQLServer (#6511) fa6bdda3c3 is described below commit fa6bdda3c33a7e49f2404faf2c375d1c59ed890f Author: TakeActionNow2019 <55011193+takeactionnow2...@users.noreply.github.com> AuthorDate: Wed Sep 11 10:01:43 2024 +0800 bugfix: the failure of rollbacking back of the delete SQL at AT mode when using SQLServer (#6511) --- changes/en-us/2.x.md | 3 + changes/zh-cn/2.x.md | 3 + .../sql/struct/cache/SqlServerTableMetaCache.java | 6 +- .../sqlserver/SqlServerUndoDeleteExecutor.java | 92 +++++++++++++++++++--- .../seata/sqlparser/struct/SqlServerTableMeta.java | 37 +++++++++ 5 files changed, 129 insertions(+), 12 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index d2df9011b8..f0ee86741f 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -24,6 +24,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6707](https://github.com/apache/incubator-seata/pull/6707)] fix readonly branch commit errors in Oracle XA transactions - [[#6711](https://github.com/apache/incubator-seata/pull/6711)] fix dameng rollback info un compress fail - [[#6714](https://github.com/apache/incubator-seata/pull/6714)] fix dameng delete undo fail +- [[#6511](https://github.com/apache/incubator-seata/pull/6511)] fix the failure of rollbacking back of the delete SQL at AT mode when using SQLServer - [[#6701](https://github.com/apache/incubator-seata/pull/6728)] fix support serialization for dm.jdbc.driver.DmdbTimestamp - [[#6757](https://github.com/apache/incubator-seata/pull/6757)] the bug where multiple nodes cannot be retrieved from the naming server - [[#6769](https://github.com/apache/incubator-seata/pull/6769)] fix tcc fence deadLock @@ -133,6 +134,7 @@ Thanks to these contributors for their code commits. Please report an unintended - [GoodBoyCoder](https://github.com/GoodBoyCoder) - [liuqiufeng](https://github.com/liuqiufeng) - [caohdgege](https://github.com/caohdgege) +- [TakeActionNow2019](https://github.com/TakeActionNow2019) - [imashimaro](https://github.com/hmj776521114) - [lyl2008dsg](https://github.com/lyl2008dsg) - [lightClouds917](https://github.com/lightClouds917) @@ -143,4 +145,5 @@ Thanks to these contributors for their code commits. Please report an unintended - [LegGasai](https://github.com/LegGasai) - [yangli-stu](https://github.com/yangli-stu) + Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index f7dd962f54..7489323f82 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -25,6 +25,7 @@ - [[#6707](https://github.com/apache/incubator-seata/pull/6707)] 修复Oracle XA事务中只读分支提交出错的问题 - [[#6711](https://github.com/apache/incubator-seata/pull/6711)] 修复达梦数据库的getRollbackInfo没有解压缩的问题 - [[#6714](https://github.com/apache/incubator-seata/pull/6714)] 修复达梦数据库的delete sql回滚失败的问题 +- [[#6511](https://github.com/apache/incubator-seata/pull/6511)] 修复在使用SQLServer时,AT模式delete语句无法正常回滚的问题 - [[#6701](https://github.com/apache/incubator-seata/pull/6728)] 修复达梦数据库的对dm.jdbc.driver.DmdbTimestamp的支持 - [[#6757](https://github.com/apache/incubator-seata/pull/6757)] 修复client通过namingserver只能获取到一个tc节点的bug - [[#6769](https://github.com/apache/incubator-seata/pull/6769)] 修复tcc fence死锁 @@ -134,6 +135,7 @@ - [GoodBoyCoder](https://github.com/GoodBoyCoder) - [liuqiufeng](https://github.com/liuqiufeng) - [caohdgege](https://github.com/caohdgege) +- [TakeActionNow2019](https://github.com/TakeActionNow2019) - [imashimaro](https://github.com/hmj776521114) - [lyl2008dsg](https://github.com/lyl2008dsg) - [lightClouds917](https://github.com/lightClouds917) @@ -144,5 +146,6 @@ - [LegGasai](https://github.com/LegGasai) - [yangli-stu](https://github.com/yangli-stu) + 同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 diff --git a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/cache/SqlServerTableMetaCache.java b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/cache/SqlServerTableMetaCache.java index 69c6fb08c4..dfe9813d30 100644 --- a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/cache/SqlServerTableMetaCache.java +++ b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/cache/SqlServerTableMetaCache.java @@ -28,6 +28,7 @@ import org.apache.seata.common.util.StringUtils; import org.apache.seata.sqlparser.struct.ColumnMeta; import org.apache.seata.sqlparser.struct.IndexMeta; import org.apache.seata.sqlparser.struct.IndexType; +import org.apache.seata.sqlparser.struct.SqlServerTableMeta; import org.apache.seata.sqlparser.struct.TableMeta; import org.apache.seata.sqlparser.util.ColumnUtils; import org.apache.seata.sqlparser.util.JdbcConstants; @@ -82,7 +83,7 @@ public class SqlServerTableMetaCache extends AbstractTableMetaCache { } private TableMeta resultSetMetaToSchema(Connection connection, String tableName) throws SQLException { - TableMeta tm = new TableMeta(); + SqlServerTableMeta tm = new SqlServerTableMeta(); tm.setTableName(tableName); tm.setOriginalTableName(tableName); @@ -134,6 +135,9 @@ public class SqlServerTableMetaCache extends AbstractTableMetaCache { col.setOrdinalPosition(rsColumns.getInt("ORDINAL_POSITION")); col.setIsNullAble(rsColumns.getString("IS_NULLABLE")); col.setIsAutoincrement(rsColumns.getString("IS_AUTOINCREMENT")); + if (col.isAutoincrement()) { + tm.setTableIdentifyExistence(true); + } if (tm.getAllColumns().containsKey(col.getColumnName())) { throw new NotSupportYetException("Not support the table has the same column name with different case yet"); diff --git a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/undo/sqlserver/SqlServerUndoDeleteExecutor.java b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/undo/sqlserver/SqlServerUndoDeleteExecutor.java index b579c599ab..caba81afa6 100644 --- a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/undo/sqlserver/SqlServerUndoDeleteExecutor.java +++ b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/undo/sqlserver/SqlServerUndoDeleteExecutor.java @@ -16,21 +16,33 @@ */ package org.apache.seata.rm.datasource.undo.sqlserver; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import org.apache.seata.common.exception.ShouldNeverHappenException; import org.apache.seata.common.util.CollectionUtils; +import org.apache.seata.common.util.IOUtil; +import org.apache.seata.rm.datasource.ConnectionProxy; import org.apache.seata.rm.datasource.sql.struct.Field; +import org.apache.seata.rm.datasource.sql.struct.KeyType; import org.apache.seata.rm.datasource.sql.struct.Row; +import org.apache.seata.rm.datasource.sql.struct.TableMetaCacheFactory; import org.apache.seata.rm.datasource.sql.struct.TableRecords; import org.apache.seata.rm.datasource.undo.SQLUndoLog; +import org.apache.seata.sqlparser.struct.SqlServerTableMeta; +import org.apache.seata.sqlparser.struct.TableMeta; import org.apache.seata.sqlparser.util.ColumnUtils; import org.apache.seata.sqlparser.util.JdbcConstants; public class SqlServerUndoDeleteExecutor extends BaseSqlServerUndoExecutor { + + private boolean tableIdentifyExistence = false; + /** * Instantiates a new sql server delete undo executor. * @@ -59,17 +71,75 @@ public class SqlServerUndoDeleteExecutor extends BaseSqlServerUndoExecutor { String insertValues = fields.stream().map(field -> "?") .collect(Collectors.joining(", ")); - return "SET IDENTITY_INSERT " + - sqlUndoLog.getTableName() + - " ON; INSERT INTO " + - sqlUndoLog.getTableName() + - " (" + - insertColumns + - ") VALUES (" + - insertValues + - "); SET IDENTITY_INSERT " + - sqlUndoLog.getTableName() + - " OFF;"; + if (tableIdentifyExistence) { + return "begin " + + "SET IDENTITY_INSERT " + sqlUndoLog.getTableName() + " ON;" + + "INSERT INTO " + sqlUndoLog.getTableName() + "(" + insertColumns + ") VALUES (" + insertValues + ");" + + "SET IDENTITY_INSERT " + sqlUndoLog.getTableName() + " OFF; " + + "end"; + } + return "INSERT INTO " + sqlUndoLog.getTableName() + "(" + insertColumns + ") VALUES (" + insertValues + ");"; + } + + /** + * Judge whether there is a column of a SQLServer table is with a "IDENTITY" + * + * @param connectionProxy + */ + private void judgeTableIdentifyExistence(ConnectionProxy connectionProxy) { + TableMeta tableMeta = TableMetaCacheFactory.getTableMetaCache(connectionProxy.getDbType()) + .getTableMeta( + connectionProxy.getTargetConnection(), + sqlUndoLog.getTableName(), + connectionProxy.getDataSourceProxy().getResourceId() + ); + tableIdentifyExistence = ((SqlServerTableMeta) tableMeta).isTableIdentifyExistence(); + } + + /** + * Execute on. + * + * @param connectionProxy the connection proxy + * @throws SQLException the sql exception + */ + @Override + public void executeOn(ConnectionProxy connectionProxy) throws SQLException { + Connection conn = connectionProxy.getTargetConnection(); + if (IS_UNDO_DATA_VALIDATION_ENABLE && !dataValidationAndGoOn(connectionProxy)) { + return; + } + + judgeTableIdentifyExistence(connectionProxy); + + PreparedStatement undoPST = null; + try { + String undoSQL = buildUndoSQL(); + undoPST = conn.prepareStatement(undoSQL); + TableRecords undoRows = getUndoRows(); + for (Row undoRow : undoRows.getRows()) { + ArrayList<Field> undoValues = new ArrayList<>(); + List<Field> pkValueList = getOrderedPkList(undoRows, undoRow, connectionProxy.getDbType()); + for (Field field : undoRow.getFields()) { + if (field.getKeyType() != KeyType.PRIMARY_KEY) { + undoValues.add(field); + } + } + + undoPrepare(undoPST, undoValues, pkValueList); + + undoPST.executeUpdate(); + } + + } catch (Exception ex) { + if (ex instanceof SQLException) { + throw (SQLException) ex; + } else { + throw new SQLException(ex); + } + } finally { + IOUtil.close(undoPST); + } + } @Override diff --git a/sqlparser/seata-sqlparser-core/src/main/java/org/apache/seata/sqlparser/struct/SqlServerTableMeta.java b/sqlparser/seata-sqlparser-core/src/main/java/org/apache/seata/sqlparser/struct/SqlServerTableMeta.java new file mode 100644 index 0000000000..8b6afbf215 --- /dev/null +++ b/sqlparser/seata-sqlparser-core/src/main/java/org/apache/seata/sqlparser/struct/SqlServerTableMeta.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.seata.sqlparser.struct; + +/** + * The type Table meta of SqlServer. + */ +public class SqlServerTableMeta extends TableMeta { + + /** + * Stands for whether there is a column of a SQLServer table with a "IDENTITY" + */ + private boolean tableIdentifyExistence = false; + + public boolean isTableIdentifyExistence() { + return tableIdentifyExistence; + } + + public void setTableIdentifyExistence(boolean tableIdentifyExistence) { + this.tableIdentifyExistence = tableIdentifyExistence; + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@seata.apache.org For additional commands, e-mail: notifications-h...@seata.apache.org