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

iamhucong 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 d2c170fa34c Refactor Oracle literal projection binding (#39280)
d2c170fa34c is described below

commit d2c170fa34c94d09d1ebf5d2e75c474c5e301284
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Thu Jul 30 19:24:53 2026 +0800

    Refactor Oracle literal projection binding (#39280)
    
    * Refactor Oracle literal projection binding
    
    * Update RELEASE-NOTES.md
---
 RELEASE-NOTES.md                                   |  1 +
 .../segment/util/SubqueryTableBindUtils.java       | 31 +++++++++++++++---
 .../statement/dml/SelectStatementBinderTest.java   | 37 ++++++++++++++++++++++
 .../OracleProjectionIdentifierExtractor.java       |  8 +++++
 .../OracleProjectionIdentifierExtractorTest.java   |  6 ++++
 5 files changed, 79 insertions(+), 4 deletions(-)

diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index d48b21b7238..10184f9e1f3 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -50,6 +50,7 @@
 1. Sharding: Fix generated actual index names exceeding database identifier 
length limits while preserving legacy generated index name compatibility - 
[#38449](https://github.com/apache/shardingsphere/pull/38449)
 1. Sharding: Fix AUTO_INTERVAL sharding failure under JVM default locales that 
use comma decimal separators - 
[#38806](https://github.com/apache/shardingsphere/pull/38806)
 1. Sharding: Compute the Snowflake key generator epoch in UTC instead of the 
JVM default timezone - 
[#38932](https://github.com/apache/shardingsphere/pull/38932)
+1. SQL Federation: Fix SQL Federation pagination binding for long LIMIT 
parameters - [#39237](https://github.com/apache/shardingsphere/pull/39237)
 
 ### Enhancements
 
diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/util/SubqueryTableBindUtils.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/util/SubqueryTableBindUtils.java
index 61949c8e0eb..c03f5f6b448 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/util/SubqueryTableBindUtils.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/util/SubqueryTableBindUtils.java
@@ -70,9 +70,9 @@ public final class SubqueryTableBindUtils {
             } else if (each instanceof ShorthandProjectionSegment) {
                 
result.addAll(createSubqueryProjections(((ShorthandProjectionSegment) 
each).getActualProjectionSegments(), subqueryTableName, databaseType, 
tableSourceType));
             } else if (each instanceof ExpressionProjectionSegment) {
-                
result.add(createColumnProjection((ExpressionProjectionSegment) each, 
subqueryTableName, databaseType));
+                
result.add(createColumnProjection((ExpressionProjectionSegment) each, 
subqueryTableName, databaseType, tableSourceType));
             } else if (each instanceof AggregationProjectionSegment) {
-                
result.add(createColumnProjection((AggregationProjectionSegment) each, 
subqueryTableName, databaseType));
+                
result.add(createColumnProjection((AggregationProjectionSegment) each, 
subqueryTableName, databaseType, tableSourceType));
             } else {
                 result.add(each);
             }
@@ -94,11 +94,14 @@ public final class SubqueryTableBindUtils {
         return result;
     }
     
-    private static ColumnProjectionSegment createColumnProjection(final 
ExpressionSegment expressionSegment, final IdentifierValue subqueryTableName, 
final DatabaseType databaseType) {
+    private static ColumnProjectionSegment createColumnProjection(final 
ExpressionSegment expressionSegment, final IdentifierValue subqueryTableName, 
final DatabaseType databaseType,
+                                                                  final 
TableSourceType tableSourceType) {
         ColumnSegment newColumnSegment = new ColumnSegment(0, 0,
                 new 
IdentifierValue(getColumnNameFromExpression(expressionSegment, databaseType), 
new 
DatabaseTypeRegistry(databaseType).getDialectDatabaseMetaData().getQuoteCharacter()));
         if (isReturnedColumnDerivedExpression(expressionSegment)) {
             setColumnBoundInfo(newColumnSegment, expressionSegment);
+        } else {
+            setColumnBoundInfo(newColumnSegment, tableSourceType);
         }
         if (!Strings.isNullOrEmpty(subqueryTableName.getValue())) {
             newColumnSegment.setOwner(new OwnerSegment(0, 0, 
subqueryTableName));
@@ -112,10 +115,30 @@ public final class SubqueryTableBindUtils {
         if (expressionSegment instanceof ExpressionProjectionSegment) {
             return 
isReturnedColumnDerivedExpression(((ExpressionProjectionSegment) 
expressionSegment).getExpr());
         }
+        if (expressionSegment instanceof CaseWhenExpression) {
+            return 
isReturnedColumnDerivedCaseWhenExpression((CaseWhenExpression) 
expressionSegment);
+        }
         if (expressionSegment instanceof FunctionSegment) {
             return 
RETURNED_COLUMN_DERIVED_FUNCTION_NAMES.contains(((FunctionSegment) 
expressionSegment).getFunctionName().toUpperCase());
         }
-        return expressionSegment instanceof CaseWhenExpression;
+        return false;
+    }
+    
+    private static boolean isReturnedColumnDerivedCaseWhenExpression(final 
CaseWhenExpression expressionSegment) {
+        if (!(expressionSegment.getElseExpr() instanceof ColumnSegment)) {
+            return false;
+        }
+        for (ExpressionSegment each : expressionSegment.getThenExprs()) {
+            if (!(each instanceof ColumnSegment)) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    private static void setColumnBoundInfo(final ColumnSegment columnSegment, 
final TableSourceType tableSourceType) {
+        TableSourceType columnTableSourceType = TableSourceType.MIXED_TABLE == 
tableSourceType ? TableSourceType.TEMPORARY_TABLE : tableSourceType;
+        columnSegment.setColumnBoundInfo(new ColumnSegmentBoundInfo(new 
TableSegmentBoundInfo(null, null), new IdentifierValue(""), 
columnSegment.getIdentifier(), columnTableSourceType));
     }
     
     private static void setColumnBoundInfo(final ColumnSegment columnSegment, 
final ExpressionSegment expressionSegment) {
diff --git 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinderTest.java
 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinderTest.java
index ba8046c52bb..1b134278ef6 100644
--- 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinderTest.java
+++ 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinderTest.java
@@ -35,6 +35,7 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.enums.TableSourceType
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.combine.CombineSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.CaseWhenExpression;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ListExpression;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonTableExpressionSegment;
@@ -59,6 +60,7 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.Windo
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WithSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.JoinTableSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SubqueryTableSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
@@ -321,6 +323,41 @@ class SelectStatementBinderTest {
         assertThat(((ColumnProjectionSegment) 
actualProjectionSegments.get(1)).getColumn().getColumnBoundInfo().getTableSourceType(),
 is(TableSourceType.TEMPORARY_TABLE));
     }
     
+    @Test
+    void assertBindWithCaseWhenLiteralBranchExpressionInSubquery() {
+        ProjectionsSegment subqueryProjections = new ProjectionsSegment(0, 0);
+        subqueryProjections.getProjections().add(new 
ColumnProjectionSegment(new ColumnSegment(0, 0, new 
IdentifierValue("user_id"))));
+        ExpressionProjectionSegment caseWhenProjection = new 
ExpressionProjectionSegment(0, 0, "CASE WHEN user_id <= 10 THEN '' ELSE 
user_name END",
+                new CaseWhenExpression(0, 0, null, Collections.singleton(new 
BinaryOperationExpression(0, 0, new ColumnSegment(0, 0, new 
IdentifierValue("user_id")),
+                        new LiteralExpressionSegment(0, 0, 10), "<=", "user_id 
<= 10")),
+                        Collections.singleton(new LiteralExpressionSegment(0, 
0, "")), new ColumnSegment(0, 0, new IdentifierValue("user_name")),
+                        "CASE WHEN user_id <= 10 THEN '' ELSE user_name END"));
+        caseWhenProjection.setAlias(new AliasSegment(0, 0, new 
IdentifierValue("a")));
+        subqueryProjections.getProjections().add(caseWhenProjection);
+        SelectStatement subquerySelectStatement = 
SelectStatement.builder().databaseType(databaseType).projections(subqueryProjections)
+                .from(new SimpleTableSegment(new TableNameSegment(0, 0, new 
IdentifierValue("t_user")))).build();
+        SubqueryTableSegment subqueryTableSegment = new 
SubqueryTableSegment(0, 0, new SubquerySegment(0, 0, subquerySelectStatement, 
""));
+        subqueryTableSegment.setAlias(new AliasSegment(0, 0, new 
IdentifierValue("text")));
+        ProjectionsSegment projections = new ProjectionsSegment(0, 0);
+        projections.getProjections().add(new ShorthandProjectionSegment(0, 0));
+        BinaryOperationExpression whereExpression =
+                new BinaryOperationExpression(0, 0, new ColumnSegment(0, 0, 
new IdentifierValue("a")), new LiteralExpressionSegment(0, 0, ""), "=", "a = 
''");
+        SelectStatement selectStatement = 
SelectStatement.builder().databaseType(databaseType).projections(projections).from(subqueryTableSegment)
+                .where(new WhereSegment(0, 0, whereExpression)).build();
+        SelectStatement actual = new 
SelectStatementBinder().bind(selectStatement,
+                new SQLStatementBinderContext(mockMetaData(), "foo_db", new 
HintValueContext(), selectStatement));
+        ProjectionSegment actualProjection = 
actual.getProjections().getProjections().iterator().next();
+        List<ProjectionSegment> actualProjectionSegments = new 
ArrayList<>(((ShorthandProjectionSegment) 
actualProjection).getActualProjectionSegments());
+        ColumnSegment actualCaseWhenProjection = ((ColumnProjectionSegment) 
actualProjectionSegments.get(1)).getColumn();
+        
assertThat(actualCaseWhenProjection.getColumnBoundInfo().getOriginalTable().getValue(),
 is(""));
+        
assertThat(actualCaseWhenProjection.getColumnBoundInfo().getOriginalColumn().getValue(),
 is("a"));
+        
assertThat(actualCaseWhenProjection.getColumnBoundInfo().getTableSourceType(), 
is(TableSourceType.TEMPORARY_TABLE));
+        ColumnSegment actualWhereColumn = (ColumnSegment) 
((BinaryOperationExpression) actual.getWhere().get().getExpr()).getLeft();
+        
assertThat(actualWhereColumn.getColumnBoundInfo().getOriginalTable().getValue(),
 is(""));
+        
assertThat(actualWhereColumn.getColumnBoundInfo().getOriginalColumn().getValue(),
 is("a"));
+        
assertThat(actualWhereColumn.getColumnBoundInfo().getTableSourceType(), 
is(TableSourceType.TEMPORARY_TABLE));
+    }
+    
     @Test
     void assertBindWithAggregationDerivedExpression() {
         ProjectionsSegment withProjections = new ProjectionsSegment(0, 0);
diff --git 
a/infra/binder/dialect/oracle/src/main/java/org/apache/shardingsphere/infra/binder/oracle/OracleProjectionIdentifierExtractor.java
 
b/infra/binder/dialect/oracle/src/main/java/org/apache/shardingsphere/infra/binder/oracle/OracleProjectionIdentifierExtractor.java
index 46f33ac3a74..b7c591e8398 100644
--- 
a/infra/binder/dialect/oracle/src/main/java/org/apache/shardingsphere/infra/binder/oracle/OracleProjectionIdentifierExtractor.java
+++ 
b/infra/binder/dialect/oracle/src/main/java/org/apache/shardingsphere/infra/binder/oracle/OracleProjectionIdentifierExtractor.java
@@ -19,6 +19,8 @@ package org.apache.shardingsphere.infra.binder.oracle;
 
 import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.extractor.DialectProjectionIdentifierExtractor;
 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.dml.item.ExpressionProjectionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 
@@ -39,6 +41,12 @@ public final class OracleProjectionIdentifierExtractor 
implements DialectProject
     
     @Override
     public String getColumnNameFromExpression(final ExpressionSegment 
expressionSegment) {
+        if (expressionSegment instanceof ExpressionProjectionSegment && 
((ExpressionProjectionSegment) expressionSegment).getExpr() instanceof 
LiteralExpressionSegment) {
+            Object literal = ((LiteralExpressionSegment) 
((ExpressionProjectionSegment) expressionSegment).getExpr()).getLiterals();
+            if (literal instanceof String) {
+                return String.format("'%s'", literal.toString().replace("'", 
"''"));
+            }
+        }
         return expressionSegment.getText().replace(" ", "").toUpperCase();
     }
     
diff --git 
a/infra/binder/dialect/oracle/src/test/java/org/apache/shardingsphere/infra/binder/oracle/OracleProjectionIdentifierExtractorTest.java
 
b/infra/binder/dialect/oracle/src/test/java/org/apache/shardingsphere/infra/binder/oracle/OracleProjectionIdentifierExtractorTest.java
index e237061da79..510f8311718 100644
--- 
a/infra/binder/dialect/oracle/src/test/java/org/apache/shardingsphere/infra/binder/oracle/OracleProjectionIdentifierExtractorTest.java
+++ 
b/infra/binder/dialect/oracle/src/test/java/org/apache/shardingsphere/infra/binder/oracle/OracleProjectionIdentifierExtractorTest.java
@@ -22,6 +22,7 @@ import 
org.apache.shardingsphere.database.connector.core.metadata.database.enums
 import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ExpressionProjectionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
@@ -53,6 +54,11 @@ class OracleProjectionIdentifierExtractorTest {
         assertThat(extractor.getColumnNameFromExpression(new 
ExpressionProjectionSegment(0, 0, "expression")), is("EXPRESSION"));
     }
     
+    @Test
+    void assertGetColumnNameFromStringLiteralExpression() {
+        assertThat(extractor.getColumnNameFromExpression(new 
ExpressionProjectionSegment(0, 7, "EXTMSG", new LiteralExpressionSegment(0, 7, 
"EXTMSG"))), is("'EXTMSG'"));
+    }
+    
     @Test
     void assertGetColumnNameFromSubquery() {
         assertThat(extractor.getColumnNameFromSubquery(new 
SubqueryProjectionSegment(mock(SubquerySegment.class), "text")), is("TEXT"));

Reply via email to