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

zhangliang 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 3c4fa846702 Remove duplicated addParameterMarkers while using 
SQLStatementCopyUtils.copyAttributes(...) and add unit tests for associated 
situations (#36262)
3c4fa846702 is described below

commit 3c4fa8467023bc28b32e0bde22adb256b9cde4a1
Author: NeatGuyCoding <[email protected]>
AuthorDate: Sun Nov 30 17:43:59 2025 +0800

    Remove duplicated addParameterMarkers while using 
SQLStatementCopyUtils.copyAttributes(...) and add unit tests for associated 
situations (#36262)
---
 .../statement/ddl/CreateTableStatementBinder.java  |   3 +-
 .../statement/ddl/PrepareStatementBinder.java      |   3 +-
 .../statement/SQLStatementCopyUtilsTest.java       | 552 +++++++++++++++++++++
 3 files changed, 556 insertions(+), 2 deletions(-)

diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/ddl/CreateTableStatementBinder.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/ddl/CreateTableStatementBinder.java
index 85571a1c8df..e59af61707d 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/ddl/CreateTableStatementBinder.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/ddl/CreateTableStatementBinder.java
@@ -57,7 +57,8 @@ public final class CreateTableStatementBinder implements 
SQLStatementBinder<Crea
         result.setSelectStatement(boundSelectStatement);
         result.getColumnDefinitions().addAll(boundColumnDefinitions);
         
result.getConstraintDefinitions().addAll(sqlStatement.getConstraintDefinitions());
-        result.addParameterMarkers(sqlStatement.getParameterMarkers());
+        // Remove duplicate addParameterMarkers call to avoid adding 
parameters twice
+        // result.addParameterMarkers(sqlStatement.getParameterMarkers());
         result.setIfNotExists(sqlStatement.isIfNotExists());
         result.getColumns().addAll(sqlStatement.getColumns());
         sqlStatement.getLikeTable().ifPresent(result::setLikeTable);
diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/ddl/PrepareStatementBinder.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/ddl/PrepareStatementBinder.java
index bd53c6a4857..f15e6ad2a4b 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/ddl/PrepareStatementBinder.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/ddl/PrepareStatementBinder.java
@@ -51,7 +51,8 @@ public final class PrepareStatementBinder implements 
SQLStatementBinder<PrepareS
         result.setInsert(boundInsert);
         result.setUpdate(boundUpdate);
         result.setDelete(boundDelete);
-        result.addParameterMarkers(sqlStatement.getParameterMarkers());
+        // Remove duplicate addParameterMarkers call to avoid adding 
parameters twice
+        // result.addParameterMarkers(sqlStatement.getParameterMarkers());
         SQLStatementCopyUtils.copyAttributes(sqlStatement, result);
         return result;
     }
diff --git 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementCopyUtilsTest.java
 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementCopyUtilsTest.java
new file mode 100644
index 00000000000..104bfa70089
--- /dev/null
+++ 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementCopyUtilsTest.java
@@ -0,0 +1,552 @@
+/*
+ * 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.shardingsphere.infra.binder.engine.statement;
+
+import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.CommentSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ParameterMarkerSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test for SQLStatementCopyUtils.
+ */
+class SQLStatementCopyUtilsTest {
+    
+    private SQLStatement originalStatement;
+    
+    private SQLStatement targetStatement;
+    
+    @BeforeEach
+    void setUp() {
+        originalStatement = new TestSQLStatement(new MockedDatabaseType());
+        targetStatement = new TestSQLStatement(new MockedDatabaseType());
+    }
+    
+    @Test
+    void assertCopyAttributesWithEmptyCollections() {
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(0, targetStatement.getParameterCount());
+        assertEquals(0, targetStatement.getParameterMarkers().size());
+        assertEquals(0, targetStatement.getVariableNames().size());
+        assertEquals(0, targetStatement.getComments().size());
+    }
+    
+    @Test
+    void assertCopyAttributesWithParameterMarkers() {
+        // Add parameter markers to original statement
+        ParameterMarkerExpressionSegment param1 = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        ParameterMarkerExpressionSegment param2 = new 
ParameterMarkerExpressionSegment(1, 1, 2);
+        originalStatement.addParameterMarkers(Arrays.asList(param1, param2));
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(2, targetStatement.getParameterCount());
+        assertEquals(2, targetStatement.getParameterMarkers().size());
+        assertTrue(targetStatement.getParameterMarkers().contains(param1));
+        assertTrue(targetStatement.getParameterMarkers().contains(param2));
+        assertTrue(targetStatement.getUniqueParameterIndexes().contains(1));
+        assertTrue(targetStatement.getUniqueParameterIndexes().contains(2));
+    }
+    
+    @Test
+    void assertCopyAttributesWithVariableNames() {
+        // Add variable names to original statement
+        originalStatement.getVariableNames().add("var1");
+        originalStatement.getVariableNames().add("var2");
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(2, targetStatement.getVariableNames().size());
+        assertTrue(targetStatement.getVariableNames().contains("var1"));
+        assertTrue(targetStatement.getVariableNames().contains("var2"));
+    }
+    
+    @Test
+    void assertCopyAttributesWithComments() {
+        // Add comments to original statement
+        CommentSegment comment1 = new CommentSegment("comment1", 0, 7);
+        CommentSegment comment2 = new CommentSegment("comment2", 8, 15);
+        originalStatement.getComments().add(comment1);
+        originalStatement.getComments().add(comment2);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(2, targetStatement.getComments().size());
+        assertTrue(targetStatement.getComments().contains(comment1));
+        assertTrue(targetStatement.getComments().contains(comment2));
+    }
+    
+    @Test
+    void assertCopyAttributesWithAllAttributes() {
+        // Add all types of attributes to original statement
+        ParameterMarkerExpressionSegment param = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        
originalStatement.addParameterMarkers(Collections.singletonList(param));
+        originalStatement.getVariableNames().add("variable");
+        CommentSegment comment = new CommentSegment("comment", 0, 6);
+        originalStatement.getComments().add(comment);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(1, targetStatement.getParameterCount());
+        assertEquals(1, targetStatement.getParameterMarkers().size());
+        assertEquals(1, targetStatement.getVariableNames().size());
+        assertEquals(1, targetStatement.getComments().size());
+        
+        assertTrue(targetStatement.getParameterMarkers().contains(param));
+        assertTrue(targetStatement.getVariableNames().contains("variable"));
+        assertTrue(targetStatement.getComments().contains(comment));
+    }
+    
+    @Test
+    void assertCopyAttributesWithDuplicateParameterMarkers() {
+        // Add parameter markers with duplicate indices
+        ParameterMarkerExpressionSegment param1 = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        // Same index as param1
+        ParameterMarkerExpressionSegment param2 = new 
ParameterMarkerExpressionSegment(1, 1, 1);
+        originalStatement.addParameterMarkers(Arrays.asList(param1, param2));
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        // Should only have one unique parameter index
+        assertEquals(1, targetStatement.getParameterCount());
+        // Both segments are added
+        assertEquals(2, targetStatement.getParameterMarkers().size());
+        assertTrue(targetStatement.getUniqueParameterIndexes().contains(1));
+    }
+    
+    @Test
+    void assertCopyAttributesWithCaseInsensitiveVariableNames() {
+        // Test case insensitive behavior of variable names
+        originalStatement.getVariableNames().add("Variable");
+        originalStatement.getVariableNames().add("variable");
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        // CaseInsensitiveSet should handle duplicates
+        assertEquals(1, targetStatement.getVariableNames().size());
+        assertTrue(targetStatement.getVariableNames().contains("Variable"));
+    }
+    
+    @Test
+    void assertCopyAttributesMultipleTimes() {
+        // Add attributes to original statement
+        ParameterMarkerExpressionSegment param = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        
originalStatement.addParameterMarkers(Collections.singletonList(param));
+        originalStatement.getVariableNames().add("var");
+        CommentSegment comment = new CommentSegment("comment", 0, 6);
+        originalStatement.getComments().add(comment);
+        
+        // Copy attributes multiple times
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        // Note: LinkedHashSet prevents duplicate object references, but 
allows different objects with same values
+        // This demonstrates why we should avoid calling addParameterMarkers 
before copyAttributes
+        // uniqueParameterIndexes.size() = 1
+        assertEquals(1, targetStatement.getParameterCount());
+        // param not duplicated due to LinkedHashSet behavior
+        assertEquals(1, targetStatement.getParameterMarkers().size());
+        // CaseInsensitiveSet handles duplicates
+        assertEquals(1, targetStatement.getVariableNames().size());
+        // LinkedList allows duplicates
+        assertEquals(2, targetStatement.getComments().size());
+    }
+    
+    @Test
+    void assertCopyAttributesWithNullCollections() {
+        // Test with null collections (should not throw exception)
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(0, targetStatement.getParameterCount());
+        assertEquals(0, targetStatement.getParameterMarkers().size());
+        assertEquals(0, targetStatement.getVariableNames().size());
+        assertEquals(0, targetStatement.getComments().size());
+    }
+    
+    @Test
+    void assertCopyAttributesWithLargeCollections() {
+        // Test with large collections
+        Collection<ParameterMarkerSegment> largeParamList = Arrays.asList(
+                new ParameterMarkerExpressionSegment(0, 0, 1),
+                new ParameterMarkerExpressionSegment(1, 1, 2),
+                new ParameterMarkerExpressionSegment(2, 2, 3),
+                new ParameterMarkerExpressionSegment(3, 3, 4),
+                new ParameterMarkerExpressionSegment(4, 4, 5));
+        originalStatement.addParameterMarkers(largeParamList);
+        
+        for (int i = 0; i < 100; i++) {
+            originalStatement.getVariableNames().add("var" + i);
+        }
+        
+        for (int i = 0; i < 50; i++) {
+            CommentSegment comment = new CommentSegment("comment" + i, i, i + 
7);
+            originalStatement.getComments().add(comment);
+        }
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(5, targetStatement.getParameterCount());
+        assertEquals(5, targetStatement.getParameterMarkers().size());
+        assertEquals(100, targetStatement.getVariableNames().size());
+        assertEquals(50, targetStatement.getComments().size());
+    }
+    
+    @Test
+    void assertCopyAttributesPreservesOrder() {
+        // Test that order is preserved for comments (LinkedList)
+        CommentSegment comment1 = new CommentSegment("first", 0, 4);
+        CommentSegment comment2 = new CommentSegment("second", 5, 10);
+        CommentSegment comment3 = new CommentSegment("third", 11, 15);
+        
+        originalStatement.getComments().add(comment1);
+        originalStatement.getComments().add(comment2);
+        originalStatement.getComments().add(comment3);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        // Convert to array to check order
+        CommentSegment[] comments = targetStatement.getComments().toArray(new 
CommentSegment[0]);
+        assertEquals(comment1, comments[0]);
+        assertEquals(comment2, comments[1]);
+        assertEquals(comment3, comments[2]);
+    }
+    
+    @Test
+    void assertCopyAttributesWithSpecialCharacters() {
+        // Test with special characters in variable names and comments
+        originalStatement.getVariableNames().add("var_with_underscore");
+        originalStatement.getVariableNames().add("var-with-dash");
+        originalStatement.getVariableNames().add("var.with.dot");
+        originalStatement.getVariableNames().add("var$with$dollar");
+        
+        CommentSegment specialComment = new CommentSegment("comment with 
special chars: !@#$%^&*()", 0, 35);
+        originalStatement.getComments().add(specialComment);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(4, targetStatement.getVariableNames().size());
+        
assertTrue(targetStatement.getVariableNames().contains("var_with_underscore"));
+        
assertTrue(targetStatement.getVariableNames().contains("var-with-dash"));
+        
assertTrue(targetStatement.getVariableNames().contains("var.with.dot"));
+        
assertTrue(targetStatement.getVariableNames().contains("var$with$dollar"));
+        
+        assertEquals(1, targetStatement.getComments().size());
+        assertTrue(targetStatement.getComments().contains(specialComment));
+    }
+    
+    @Test
+    void assertCopyAttributesWithEmptyStrings() {
+        // Test with empty strings
+        originalStatement.getVariableNames().add("");
+        originalStatement.getVariableNames().add("   ");
+        CommentSegment emptyComment = new CommentSegment("", 0, 0);
+        originalStatement.getComments().add(emptyComment);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(2, targetStatement.getVariableNames().size());
+        assertTrue(targetStatement.getVariableNames().contains(""));
+        assertTrue(targetStatement.getVariableNames().contains("   "));
+        
+        assertEquals(1, targetStatement.getComments().size());
+        assertTrue(targetStatement.getComments().contains(emptyComment));
+    }
+    
+    @Test
+    void assertCopyAttributesWithUnicodeCharacters() {
+        // Test with Unicode characters
+        originalStatement.getVariableNames().add("变量名");
+        originalStatement.getVariableNames().add("変数名");
+        originalStatement.getVariableNames().add("변수명");
+        
+        CommentSegment unicodeComment = new CommentSegment("Unicode comment: 
你好世界", 0, 20);
+        originalStatement.getComments().add(unicodeComment);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(3, targetStatement.getVariableNames().size());
+        assertTrue(targetStatement.getVariableNames().contains("变量名"));
+        assertTrue(targetStatement.getVariableNames().contains("変数名"));
+        assertTrue(targetStatement.getVariableNames().contains("변수명"));
+        
+        assertEquals(1, targetStatement.getComments().size());
+        assertTrue(targetStatement.getComments().contains(unicodeComment));
+    }
+    
+    @Test
+    void assertCopyAttributesWithBoundaryValues() {
+        // Test with boundary values for parameter indices
+        ParameterMarkerExpressionSegment minParam = new 
ParameterMarkerExpressionSegment(0, 0, Integer.MIN_VALUE);
+        ParameterMarkerExpressionSegment maxParam = new 
ParameterMarkerExpressionSegment(1, 1, Integer.MAX_VALUE);
+        ParameterMarkerExpressionSegment zeroParam = new 
ParameterMarkerExpressionSegment(2, 2, 0);
+        ParameterMarkerExpressionSegment negativeParam = new 
ParameterMarkerExpressionSegment(3, 3, -1);
+        
+        originalStatement.addParameterMarkers(Arrays.asList(minParam, 
maxParam, zeroParam, negativeParam));
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(4, targetStatement.getParameterCount());
+        assertEquals(4, targetStatement.getParameterMarkers().size());
+        
assertTrue(targetStatement.getUniqueParameterIndexes().contains(Integer.MIN_VALUE));
+        
assertTrue(targetStatement.getUniqueParameterIndexes().contains(Integer.MAX_VALUE));
+        assertTrue(targetStatement.getUniqueParameterIndexes().contains(0));
+        assertTrue(targetStatement.getUniqueParameterIndexes().contains(-1));
+    }
+    
+    @Test
+    void assertCopyAttributesWithMixedContent() {
+        // Test with mixed content types
+        ParameterMarkerExpressionSegment param = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        
originalStatement.addParameterMarkers(Collections.singletonList(param));
+        
+        originalStatement.getVariableNames().add("mixed_var");
+        originalStatement.getVariableNames().add("123numeric");
+        originalStatement.getVariableNames().add("_underscore_start");
+        
+        CommentSegment mixedComment = new CommentSegment("Mixed comment: 123 
!@# 变量", 0, 25);
+        originalStatement.getComments().add(mixedComment);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        assertEquals(1, targetStatement.getParameterCount());
+        assertEquals(3, targetStatement.getVariableNames().size());
+        assertEquals(1, targetStatement.getComments().size());
+        
+        assertTrue(targetStatement.getVariableNames().contains("mixed_var"));
+        assertTrue(targetStatement.getVariableNames().contains("123numeric"));
+        
assertTrue(targetStatement.getVariableNames().contains("_underscore_start"));
+        assertTrue(targetStatement.getComments().contains(mixedComment));
+    }
+    
+    @Test
+    void assertCopyAttributesEquivalentToManualCopy() {
+        // Test that copyAttributes is equivalent to manual copying
+        ParameterMarkerExpressionSegment param1 = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        ParameterMarkerExpressionSegment param2 = new 
ParameterMarkerExpressionSegment(1, 1, 2);
+        originalStatement.addParameterMarkers(Arrays.asList(param1, param2));
+        
+        originalStatement.getVariableNames().add("var1");
+        originalStatement.getVariableNames().add("var2");
+        
+        CommentSegment comment1 = new CommentSegment("comment1", 0, 7);
+        CommentSegment comment2 = new CommentSegment("comment2", 8, 15);
+        originalStatement.getComments().add(comment1);
+        originalStatement.getComments().add(comment2);
+        
+        // Method 1: Using copyAttributes
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        // Method 2: Manual copying (equivalent to what copyAttributes does)
+        SQLStatement manualCopyStatement = new TestSQLStatement(new 
MockedDatabaseType());
+        
manualCopyStatement.addParameterMarkers(originalStatement.getParameterMarkers());
+        
manualCopyStatement.getVariableNames().addAll(originalStatement.getVariableNames());
+        
manualCopyStatement.getComments().addAll(originalStatement.getComments());
+        
+        // Both should have the same result
+        assertEquals(targetStatement.getParameterCount(), 
manualCopyStatement.getParameterCount());
+        assertEquals(targetStatement.getParameterMarkers().size(), 
manualCopyStatement.getParameterMarkers().size());
+        assertEquals(targetStatement.getVariableNames().size(), 
manualCopyStatement.getVariableNames().size());
+        assertEquals(targetStatement.getComments().size(), 
manualCopyStatement.getComments().size());
+        
+        
assertTrue(targetStatement.getParameterMarkers().containsAll(manualCopyStatement.getParameterMarkers()));
+        
assertTrue(targetStatement.getVariableNames().containsAll(manualCopyStatement.getVariableNames()));
+        
assertTrue(targetStatement.getComments().containsAll(manualCopyStatement.getComments()));
+    }
+    
+    @Test
+    void assertDuplicateAddParameterMarkersBehavior() {
+        // Test the behavior of duplicate addParameterMarkers calls
+        ParameterMarkerExpressionSegment param = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        
+        // First call
+        targetStatement.addParameterMarkers(Collections.singletonList(param));
+        assertEquals(1, targetStatement.getParameterMarkers().size());
+        assertEquals(1, targetStatement.getParameterCount());
+        
+        // Second call with the same parameter object (same reference)
+        targetStatement.addParameterMarkers(Collections.singletonList(param));
+        // LinkedHashSet prevents duplicate object references
+        assertEquals(1, targetStatement.getParameterMarkers().size());
+        // uniqueParameterIndexes still 1 due to same index
+        assertEquals(1, targetStatement.getParameterCount());
+        
+        // Third call with a new parameter object but same index
+        // Same index, different position
+        ParameterMarkerExpressionSegment param2 = new 
ParameterMarkerExpressionSegment(1, 1, 1);
+        targetStatement.addParameterMarkers(Collections.singletonList(param2));
+        // Different object added
+        assertEquals(2, targetStatement.getParameterMarkers().size());
+        // uniqueParameterIndexes still 1 due to same index
+        assertEquals(1, targetStatement.getParameterCount());
+    }
+    
+    @Test
+    void assertSQLStatementAddParameterMarkersBehavior() {
+        // Test SQLStatement's addParameterMarkers method directly
+        final ParameterMarkerExpressionSegment param1 = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        final ParameterMarkerExpressionSegment param2 = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        
+        // First call
+        targetStatement.addParameterMarkers(Collections.singletonList(param1));
+        assertEquals(1, targetStatement.getParameterMarkers().size(), "First 
parameter should be added");
+        assertEquals(1, targetStatement.getUniqueParameterIndexes().size(), 
"Should have one unique parameter index");
+        assertEquals(1, targetStatement.getParameterCount(), "Parameter count 
should be 1");
+        
+        // Second call with the same parameter object (same reference)
+        targetStatement.addParameterMarkers(Collections.singletonList(param1));
+        assertEquals(1, targetStatement.getParameterMarkers().size(), "Same 
object should not be added again");
+        assertEquals(1, targetStatement.getUniqueParameterIndexes().size(), 
"Unique parameter index count should remain 1");
+        assertEquals(1, targetStatement.getParameterCount(), "Parameter count 
should remain 1");
+        
+        // Third call with a new parameter object but same index
+        targetStatement.addParameterMarkers(Collections.singletonList(param2));
+        assertEquals(2, targetStatement.getParameterMarkers().size(), 
"Different object should be added");
+        assertEquals(1, targetStatement.getUniqueParameterIndexes().size(), 
"Unique parameter index count should remain 1");
+        assertEquals(1, targetStatement.getParameterCount(), "Parameter count 
should remain 1");
+        
+        // Verify the behavior: LinkedHashSet prevents duplicate object 
references
+        assertTrue(targetStatement.getParameterMarkers().contains(param1), 
"First parameter should be in the set");
+        assertTrue(targetStatement.getParameterMarkers().contains(param2), 
"Second parameter should be in the set");
+    }
+    
+    @Test
+    void assertCopyAttributesWithDuplicateVariableNames() {
+        // Test that duplicate variable names are handled correctly
+        originalStatement.getVariableNames().add("duplicate");
+        // Add same name twice
+        originalStatement.getVariableNames().add("duplicate");
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        // CaseInsensitiveSet should handle duplicates
+        assertEquals(1, targetStatement.getVariableNames().size());
+        assertTrue(targetStatement.getVariableNames().contains("duplicate"));
+    }
+    
+    @Test
+    void assertCopyAttributesWithDuplicateComments() {
+        // Test that duplicate comments are handled correctly
+        CommentSegment comment = new CommentSegment("duplicate", 0, 8);
+        originalStatement.getComments().add(comment);
+        // Add same comment twice
+        originalStatement.getComments().add(comment);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        // LinkedList allows duplicates
+        assertEquals(2, targetStatement.getComments().size());
+        assertTrue(targetStatement.getComments().contains(comment));
+    }
+    
+    @Test
+    void assertCopyAttributesWithNullValues() {
+        // Test that null values are handled correctly
+        originalStatement.getVariableNames().add(null);
+        originalStatement.getComments().add(null);
+        
+        SQLStatementCopyUtils.copyAttributes(originalStatement, 
targetStatement);
+        
+        // Should handle null values gracefully
+        assertEquals(1, targetStatement.getVariableNames().size());
+        assertEquals(1, targetStatement.getComments().size());
+        assertTrue(targetStatement.getVariableNames().contains(null));
+        assertTrue(targetStatement.getComments().contains(null));
+    }
+    
+    @Test
+    void assertParameterMarkerExpressionSegmentEquality() {
+        // Test that ParameterMarkerExpressionSegment objects with same values 
are NOT considered equal
+        // because they don't override equals() and hashCode()
+        ParameterMarkerExpressionSegment param1 = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        ParameterMarkerExpressionSegment param2 = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        
+        // These should NOT be equal because they use default object reference 
comparison
+        assertFalse(param1.equals(param2));
+        assertFalse(param1.hashCode() == param2.hashCode());
+        
+        // Add both to a LinkedHashSet
+        originalStatement.addParameterMarkers(Arrays.asList(param1, param2));
+        
+        // Both should be added because LinkedHashSet treats them as different 
objects
+        assertEquals(2, originalStatement.getParameterMarkers().size());
+        // Same parameter index
+        assertEquals(1, originalStatement.getParameterCount());
+    }
+    
+    @Test
+    void assertParameterMarkerExpressionSegmentInequality() {
+        // Test that ParameterMarkerExpressionSegment objects with different 
values are not equal
+        ParameterMarkerExpressionSegment param1 = new 
ParameterMarkerExpressionSegment(0, 0, 1);
+        // Different start/stop indices
+        ParameterMarkerExpressionSegment param2 = new 
ParameterMarkerExpressionSegment(1, 1, 1);
+        // Different parameter index
+        ParameterMarkerExpressionSegment param3 = new 
ParameterMarkerExpressionSegment(0, 0, 2);
+        
+        // These should not be equal
+        assertFalse(param1.equals(param2));
+        assertFalse(param1.equals(param3));
+        
+        // Add all three to a LinkedHashSet
+        originalStatement.addParameterMarkers(Arrays.asList(param1, param2, 
param3));
+        
+        // All three should be added because they are different
+        assertEquals(3, originalStatement.getParameterMarkers().size());
+        // param1 and param3 have same index 1
+        assertEquals(2, originalStatement.getParameterCount());
+    }
+    
+    /**
+     * Test SQL statement implementation for testing purposes.
+     */
+    private static class TestSQLStatement extends SQLStatement {
+        
+        TestSQLStatement(final MockedDatabaseType databaseType) {
+            super(databaseType);
+        }
+        
+        // Expose protected methods for testing
+        public Collection<Integer> getUniqueParameterIndexes() {
+            return super.getUniqueParameterIndexes();
+        }
+    }
+    
+    static class MockedDatabaseType implements DatabaseType {
+        
+        @Override
+        public Collection<String> getJdbcUrlPrefixes() {
+            return Collections.singleton("jdbc:mock");
+        }
+        
+        @Override
+        public String getType() {
+            return "MOCKED";
+        }
+    }
+}

Reply via email to