This is an automated email from the ASF dual-hosted git repository.

zhaojinchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new d09418bc104 Refactor AbstractSQLBuilder logic and add getStopIndex in 
SQLToken (#33451)
d09418bc104 is described below

commit d09418bc104ec7130c46abb8cfc89ccd39070285
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Tue Oct 29 17:23:53 2024 +0800

    Refactor AbstractSQLBuilder logic and add getStopIndex in SQLToken (#33451)
    
    * Refactor AbstractSQLBuilder logic and add getStopIndex in SQLToken
    
    * fix checkstyle
---
 .../InsertSelectColumnsEncryptorComparator.java           | 15 +++++++++++++++
 .../insert/EncryptInsertCipherNameTokenGenerator.java     | 14 ++++++++++----
 .../rewrite/token/pojo/DistinctProjectionPrefixToken.java |  5 +++++
 .../sharding/rewrite/token/pojo/OrderByToken.java         |  5 +++++
 .../sharding/rewrite/token/pojo/ProjectionsToken.java     |  5 +++++
 .../context/statement/dml/InsertStatementContext.java     |  8 ++++++++
 .../infra/rewrite/sql/impl/AbstractSQLBuilder.java        | 14 +++++++++++---
 .../infra/rewrite/sql/token/common/pojo/SQLToken.java     |  7 +++++++
 .../token/common/pojo/generic/ColumnDefinitionToken.java  |  5 +++++
 .../sql/token/common/pojo/generic/InsertColumnsToken.java |  5 +++++
 .../common/pojo/generic/UseDefaultInsertColumnsToken.java |  5 +++++
 .../token/keygen/pojo/GeneratedKeyAssignmentToken.java    |  5 +++++
 .../token/keygen/pojo/GeneratedKeyInsertColumnToken.java  |  5 +++++
 .../infra/rewrite/sql/impl/RouteSQLBuilderTest.java       |  7 +++++++
 .../visitor/statement/type/OracleDMLStatementVisitor.java |  5 ++++-
 15 files changed, 102 insertions(+), 8 deletions(-)

diff --git 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/comparator/InsertSelectColumnsEncryptorComparator.java
 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/comparator/InsertSelectColumnsEncryptorComparator.java
index 704698239b6..20ea0dbf696 100644
--- 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/comparator/InsertSelectColumnsEncryptorComparator.java
+++ 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/comparator/InsertSelectColumnsEncryptorComparator.java
@@ -23,7 +23,11 @@ import org.apache.shardingsphere.encrypt.rule.EncryptRule;
 import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;
 import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.Projection;
 import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection;
+import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ExpressionProjection;
+import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ParameterMarkerProjection;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 
@@ -52,6 +56,9 @@ public final class InsertSelectColumnsEncryptorComparator {
             EncryptAlgorithm insertColumnEncryptor = 
encryptRule.findQueryEncryptor(
                     
insertColumnSegment.getColumnBoundInfo().getOriginalTable().getValue(), 
insertColumnSegment.getColumnBoundInfo().getOriginalColumn().getValue()).orElse(null);
             Projection projection = projectionIterator.next();
+            if (isLiteralOrParameterMarker(projection)) {
+                continue;
+            }
             ColumnSegmentBoundInfo projectionColumnBoundInfo = 
getColumnSegmentBoundInfo(projection);
             EncryptAlgorithm projectionEncryptor =
                     
encryptRule.findQueryEncryptor(projectionColumnBoundInfo.getOriginalTable().getValue(),
 projectionColumnBoundInfo.getOriginalColumn().getValue()).orElse(null);
@@ -62,6 +69,14 @@ public final class InsertSelectColumnsEncryptorComparator {
         return true;
     }
     
+    private static boolean isLiteralOrParameterMarker(final Projection 
projection) {
+        if (projection instanceof ExpressionProjection) {
+            ExpressionSegment expressionSegment = ((ExpressionProjection) 
projection).getExpressionSegment().getExpr();
+            return expressionSegment instanceof LiteralExpressionSegment;
+        }
+        return projection instanceof ParameterMarkerProjection;
+    }
+    
     private static ColumnSegmentBoundInfo getColumnSegmentBoundInfo(final 
Projection projection) {
         return projection instanceof ColumnProjection
                 ? new ColumnSegmentBoundInfo(null, null, ((ColumnProjection) 
projection).getOriginalTable(), ((ColumnProjection) 
projection).getOriginalColumn())
diff --git 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/insert/EncryptInsertCipherNameTokenGenerator.java
 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/insert/EncryptInsertCipherNameTokenGenerator.java
index 3809f34ddee..989421390da 100644
--- 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/insert/EncryptInsertCipherNameTokenGenerator.java
+++ 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/insert/EncryptInsertCipherNameTokenGenerator.java
@@ -28,6 +28,7 @@ import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.
 import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection;
 import 
org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
 import 
org.apache.shardingsphere.infra.binder.context.statement.dml.InsertStatementContext;
+import 
org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext;
 import 
org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
 import 
org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
 import 
org.apache.shardingsphere.infra.rewrite.sql.token.common.generator.CollectionSQLTokenGenerator;
@@ -66,10 +67,7 @@ public final class EncryptInsertCipherNameTokenGenerator 
implements CollectionSQ
         Preconditions.checkState(insertColumnsSegment.isPresent());
         Collection<ColumnSegment> insertColumns = 
insertColumnsSegment.get().getColumns();
         if (null != insertStatementContext.getInsertSelectContext()) {
-            Collection<Projection> projections = 
insertStatementContext.getInsertSelectContext().getSelectStatementContext().getProjectionsContext().getExpandProjections();
-            ShardingSpherePreconditions.checkState(insertColumns.size() == 
projections.size(), () -> new UnsupportedSQLOperationException("Column count 
doesn't match value count."));
-            
ShardingSpherePreconditions.checkState(InsertSelectColumnsEncryptorComparator.isSame(insertColumns,
 projections, encryptRule),
-                    () -> new UnsupportedSQLOperationException("Can not use 
different encryptor in insert select columns"));
+            
checkInsertSelectEncryptor(insertStatementContext.getInsertSelectContext().getSelectStatementContext(),
 insertColumns);
         }
         EncryptTable encryptTable = 
encryptRule.getEncryptTable(insertStatementContext.getSqlStatement().getTable().map(optional
 -> optional.getTableName().getIdentifier().getValue()).orElse(""));
         Collection<SQLToken> result = new LinkedList<>();
@@ -83,4 +81,12 @@ public final class EncryptInsertCipherNameTokenGenerator 
implements CollectionSQ
         }
         return result;
     }
+    
+    private void checkInsertSelectEncryptor(final SelectStatementContext 
selectStatementContext, final Collection<ColumnSegment> insertColumns) {
+        Collection<Projection> projections = 
selectStatementContext.getProjectionsContext().getExpandProjections();
+        ShardingSpherePreconditions.checkState(insertColumns.size() == 
projections.size(), () -> new UnsupportedSQLOperationException("Column count 
doesn't match value count."));
+        
ShardingSpherePreconditions.checkState(InsertSelectColumnsEncryptorComparator.isSame(insertColumns,
 projections, encryptRule),
+                () -> new UnsupportedSQLOperationException("Can not use 
different encryptor in insert select columns"));
+        selectStatementContext.getSubqueryContexts().values().forEach(each -> 
checkInsertSelectEncryptor(each, insertColumns));
+    }
 }
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/DistinctProjectionPrefixToken.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/DistinctProjectionPrefixToken.java
index de405fee685..eedbc5a0b93 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/DistinctProjectionPrefixToken.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/DistinctProjectionPrefixToken.java
@@ -33,4 +33,9 @@ public final class DistinctProjectionPrefixToken extends 
SQLToken implements Att
     public String toString() {
         return "DISTINCT ";
     }
+    
+    @Override
+    public int getStopIndex() {
+        return getStartIndex();
+    }
 }
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/OrderByToken.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/OrderByToken.java
index bf32e6b073e..5bd613f31d1 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/OrderByToken.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/OrderByToken.java
@@ -53,4 +53,9 @@ public final class OrderByToken extends SQLToken implements 
Attachable {
         result.append(' ');
         return result.toString();
     }
+    
+    @Override
+    public int getStopIndex() {
+        return getStartIndex();
+    }
 }
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/ProjectionsToken.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/ProjectionsToken.java
index 2227f902e96..0088eb5c924 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/ProjectionsToken.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/ProjectionsToken.java
@@ -46,4 +46,9 @@ public final class ProjectionsToken extends SQLToken 
implements Attachable, Rout
         }
         return result.toString();
     }
+    
+    @Override
+    public int getStopIndex() {
+        return getStartIndex();
+    }
 }
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/InsertStatementContext.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/InsertStatementContext.java
index 04417de0da9..5bea4c943ee 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/InsertStatementContext.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/InsertStatementContext.java
@@ -41,6 +41,7 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignmen
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.OnDuplicateKeyColumnsSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.combine.CombineSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
@@ -137,6 +138,13 @@ public final class InsertStatementContext extends 
CommonSQLStatementContext impl
         SubquerySegment insertSelectSegment = 
getSqlStatement().getInsertSelect().get();
         SelectStatementContext selectStatementContext = new 
SelectStatementContext(metaData, params, insertSelectSegment.getSelect(), 
currentDatabaseName, Collections.emptyList());
         selectStatementContext.setSubqueryType(SubqueryType.INSERT_SELECT);
+        if (selectStatementContext.getSqlStatement().getCombine().isPresent()) 
{
+            CombineSegment combineSegment = 
selectStatementContext.getSqlStatement().getCombine().get();
+            
Optional.ofNullable(selectStatementContext.getSubqueryContexts().get(combineSegment.getLeft().getStartIndex()))
+                    .ifPresent(optional -> 
optional.setSubqueryType(SubqueryType.INSERT_SELECT));
+            
Optional.ofNullable(selectStatementContext.getSubqueryContexts().get(combineSegment.getRight().getStartIndex()))
+                    .ifPresent(optional -> 
optional.setSubqueryType(SubqueryType.INSERT_SELECT));
+        }
         InsertSelectContext insertSelectContext = new 
InsertSelectContext(selectStatementContext, params, paramsOffset.get());
         paramsOffset.addAndGet(insertSelectContext.getParameterCount());
         return Optional.of(insertSelectContext);
diff --git 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/impl/AbstractSQLBuilder.java
 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/impl/AbstractSQLBuilder.java
index 55135dc1219..f5f409756bc 100644
--- 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/impl/AbstractSQLBuilder.java
+++ 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/impl/AbstractSQLBuilder.java
@@ -25,6 +25,7 @@ import 
org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.generic.Com
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * Abstract SQL builder.
@@ -44,13 +45,18 @@ public abstract class AbstractSQLBuilder implements 
SQLBuilder {
         Collections.sort(sqlTokens);
         StringBuilder result = new StringBuilder(sql.length());
         result.append(sql, 0, sqlTokens.get(0).getStartIndex());
+        Optional<SQLToken> previousToken = Optional.empty();
         for (SQLToken each : sqlTokens) {
+            if (each.getStartIndex() < 
previousToken.map(SQLToken::getStopIndex).orElse(0)) {
+                continue;
+            }
             if (each instanceof ComposableSQLToken) {
                 result.append(getComposableSQLTokenText((ComposableSQLToken) 
each));
             } else {
                 result.append(getSQLTokenText(each));
             }
             result.append(getConjunctionText(each));
+            previousToken = Optional.of(each);
         }
         return result.toString();
     }
@@ -67,7 +73,8 @@ public abstract class AbstractSQLBuilder implements 
SQLBuilder {
     }
     
     private String getConjunctionText(final SQLToken sqlToken) {
-        return sql.substring(getStartIndex(sqlToken), getStopIndex(sqlToken));
+        int startIndex = getStartIndex(sqlToken);
+        return sql.substring(startIndex, getStopIndex(sqlToken, startIndex));
     }
     
     private int getStartIndex(final SQLToken sqlToken) {
@@ -75,8 +82,9 @@ public abstract class AbstractSQLBuilder implements 
SQLBuilder {
         return Math.min(startIndex, sql.length());
     }
     
-    private int getStopIndex(final SQLToken sqlToken) {
+    private int getStopIndex(final SQLToken sqlToken, final int startIndex) {
         int currentSQLTokenIndex = sqlTokens.indexOf(sqlToken);
-        return sqlTokens.size() - 1 == currentSQLTokenIndex ? sql.length() : 
sqlTokens.get(currentSQLTokenIndex + 1).getStartIndex();
+        int stopIndex = sqlTokens.size() - 1 == currentSQLTokenIndex ? 
sql.length() : sqlTokens.get(currentSQLTokenIndex + 1).getStartIndex();
+        return startIndex <= stopIndex ? stopIndex : 
getStopIndex(sqlTokens.get(currentSQLTokenIndex + 1), startIndex);
     }
 }
diff --git 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/SQLToken.java
 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/SQLToken.java
index 9c6c15bd2f6..809a1e47dab 100644
--- 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/SQLToken.java
+++ 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/SQLToken.java
@@ -33,4 +33,11 @@ public abstract class SQLToken implements 
Comparable<SQLToken> {
     public final int compareTo(final SQLToken sqlToken) {
         return startIndex - sqlToken.startIndex;
     }
+    
+    /**
+     * Get stop index.
+     *
+     * @return stop index
+     */
+    public abstract int getStopIndex();
 }
diff --git 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/ColumnDefinitionToken.java
 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/ColumnDefinitionToken.java
index bd62611b110..bb873743422 100644
--- 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/ColumnDefinitionToken.java
+++ 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/ColumnDefinitionToken.java
@@ -47,4 +47,9 @@ public final class ColumnDefinitionToken extends SQLToken {
         }
         return columnName + " " + dataType;
     }
+    
+    @Override
+    public int getStopIndex() {
+        return getStartIndex();
+    }
 }
diff --git 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/InsertColumnsToken.java
 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/InsertColumnsToken.java
index 78dd3ed9c16..1fb4a04ab20 100644
--- 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/InsertColumnsToken.java
+++ 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/InsertColumnsToken.java
@@ -44,4 +44,9 @@ public final class InsertColumnsToken extends SQLToken 
implements Attachable {
         columns.forEach(result::add);
         return result.toString();
     }
+    
+    @Override
+    public int getStopIndex() {
+        return getStartIndex();
+    }
 }
diff --git 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/UseDefaultInsertColumnsToken.java
 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/UseDefaultInsertColumnsToken.java
index 708a9b9c3dd..47f16babb6e 100644
--- 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/UseDefaultInsertColumnsToken.java
+++ 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/common/pojo/generic/UseDefaultInsertColumnsToken.java
@@ -40,4 +40,9 @@ public final class UseDefaultInsertColumnsToken extends 
SQLToken implements Atta
     public String toString() {
         return columns.isEmpty() ? "" : "(" + String.join(", ", columns) + ")";
     }
+    
+    @Override
+    public int getStopIndex() {
+        return getStartIndex();
+    }
 }
diff --git 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/keygen/pojo/GeneratedKeyAssignmentToken.java
 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/keygen/pojo/GeneratedKeyAssignmentToken.java
index 90a3546ab82..39517efb7af 100644
--- 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/keygen/pojo/GeneratedKeyAssignmentToken.java
+++ 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/keygen/pojo/GeneratedKeyAssignmentToken.java
@@ -38,4 +38,9 @@ public abstract class GeneratedKeyAssignmentToken extends 
SQLToken implements At
     }
     
     protected abstract String getRightValue();
+    
+    @Override
+    public int getStopIndex() {
+        return getStartIndex();
+    }
 }
diff --git 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/keygen/pojo/GeneratedKeyInsertColumnToken.java
 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/keygen/pojo/GeneratedKeyInsertColumnToken.java
index a62878a9e56..0f70e822163 100644
--- 
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/keygen/pojo/GeneratedKeyInsertColumnToken.java
+++ 
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/keygen/pojo/GeneratedKeyInsertColumnToken.java
@@ -36,4 +36,9 @@ public final class GeneratedKeyInsertColumnToken extends 
SQLToken implements Att
     public String toString() {
         return ", " + column;
     }
+    
+    @Override
+    public int getStopIndex() {
+        return getStartIndex();
+    }
 }
diff --git 
a/infra/rewrite/src/test/java/org/apache/shardingsphere/infra/rewrite/sql/impl/RouteSQLBuilderTest.java
 
b/infra/rewrite/src/test/java/org/apache/shardingsphere/infra/rewrite/sql/impl/RouteSQLBuilderTest.java
index f32872d75e4..a79f4efbe17 100644
--- 
a/infra/rewrite/src/test/java/org/apache/shardingsphere/infra/rewrite/sql/impl/RouteSQLBuilderTest.java
+++ 
b/infra/rewrite/src/test/java/org/apache/shardingsphere/infra/rewrite/sql/impl/RouteSQLBuilderTest.java
@@ -23,6 +23,7 @@ import 
org.apache.shardingsphere.infra.route.context.RouteMapper;
 import org.apache.shardingsphere.infra.route.context.RouteUnit;
 import org.junit.jupiter.api.Test;
 
+import java.util.Arrays;
 import java.util.Collections;
 
 import static org.hamcrest.CoreMatchers.is;
@@ -36,6 +37,12 @@ class RouteSQLBuilderTest {
         assertThat(new RouteSQLBuilder("SELECT * FROM tbl WHERE id=?", 
Collections.singletonList(new SQLTokenFixture(14, 16)), 
createRouteUnit()).toSQL(), is("SELECT * FROM XXX WHERE id=?"));
     }
     
+    @Test
+    void assertToSQLWithDuplicateSQLToken() {
+        assertThat(new RouteSQLBuilder("SELECT * FROM tbl WHERE id=?", 
Arrays.asList(new SQLTokenFixture(14, 16), new SQLTokenFixture(14, 16)), 
createRouteUnit()).toSQL(),
+                is("SELECT * FROM XXX WHERE id=?"));
+    }
+    
     @Test
     void assertToSQLWithRouteUnitAwareSQLToken() {
         assertThat(new RouteSQLBuilder("SELECT * FROM tbl WHERE id=?", 
Collections.singletonList(new RouteUnitAwareSQLTokenFixture(14, 16)), 
createRouteUnit()).toSQL(),
diff --git 
a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
 
b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
index 303692d7b01..0afbf8134c6 100644
--- 
a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
+++ 
b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
@@ -614,8 +614,11 @@ public final class OracleDMLStatementVisitor extends 
OracleStatementVisitor impl
         } else {
             combineType = CombineType.MINUS;
         }
+        OracleSelectStatement right = (OracleSelectStatement) 
visit(ctx.selectSubquery(1));
         result.setCombine(new CombineSegment(ctx.getStart().getStartIndex(), 
ctx.getStop().getStopIndex(), createSubquerySegment(ctx.selectSubquery(0), 
left), combineType,
-                createSubquerySegment(ctx.selectSubquery(1), 
(OracleSelectStatement) visit(ctx.selectSubquery(1)))));
+                createSubquerySegment(ctx.selectSubquery(1), right)));
+        result.addParameterMarkerSegments(left.getParameterMarkerSegments());
+        result.addParameterMarkerSegments(right.getParameterMarkerSegments());
     }
     
     private SubquerySegment createSubquerySegment(final SelectSubqueryContext 
ctx, final OracleSelectStatement selectStatement) {

Reply via email to