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

terrymanu 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 7abc3480a65 Fix firebird order by nulls (#40179)
7abc3480a65 is described below

commit 7abc3480a6580dc7d7fd4ccb0fc36e828cd398b3
Author: Maxim Igoshin <[email protected]>
AuthorDate: Sat Oct 17 04:56:22 2026 +0300

    Fix firebird order by nulls (#40179)
    
    * Support NULLS FIRST and NULLS LAST in Firebird ORDER BY
    
    * Fix CODE_OF_CONDUCT violations in Firebird ORDER BY NULLS parsing
---
 .../src/main/antlr4/imports/firebird/BaseRule.g4   |  4 +-
 .../antlr4/imports/firebird/FirebirdKeyword.g4     |  4 ++
 .../statement/FirebirdStatementVisitor.java        | 17 ++++++--
 .../main/resources/case/dml/select-order-by.xml    | 48 ++++++++++++++++++++++
 .../sql/supported/dml/select-order-by.xml          |  3 ++
 5 files changed, 71 insertions(+), 5 deletions(-)

diff --git 
a/parser/sql/engine/dialect/firebird/src/main/antlr4/imports/firebird/BaseRule.g4
 
b/parser/sql/engine/dialect/firebird/src/main/antlr4/imports/firebird/BaseRule.g4
index 333ffdfa9ef..8901ee0789f 100644
--- 
a/parser/sql/engine/dialect/firebird/src/main/antlr4/imports/firebird/BaseRule.g4
+++ 
b/parser/sql/engine/dialect/firebird/src/main/antlr4/imports/firebird/BaseRule.g4
@@ -76,7 +76,7 @@ unreservedWord
     | FORTRAN
     | LENGTH
     | MESSAGE_LENGTH | MESSAGE_OCTET_LENGTH | MESSAGE_TEXT | MORE92 | MUMPS
-    | NAME | NULLABLE | NUMBER
+    | NAME | NULLABLE | NULLS | NUMBER
     | ORDER
     | PASCAL | PLI
     | REPEATABLE | RETURNED_LENGTH | RETURNED_OCTET_LENGTH | RETURNED_SQLSTATE 
| ROW_COUNT
@@ -394,7 +394,7 @@ orderByClause
     ;
 
 orderByItem
-    : (numberLiterals | expr) (ASC | DESC)?
+    : (numberLiterals | expr) (ASC | DESC)? (NULLS FIRST | NULLS LAST)?
     ;
 
 limitClause
diff --git 
a/parser/sql/engine/dialect/firebird/src/main/antlr4/imports/firebird/FirebirdKeyword.g4
 
b/parser/sql/engine/dialect/firebird/src/main/antlr4/imports/firebird/FirebirdKeyword.g4
index 238b894e458..efaf7108d31 100644
--- 
a/parser/sql/engine/dialect/firebird/src/main/antlr4/imports/firebird/FirebirdKeyword.g4
+++ 
b/parser/sql/engine/dialect/firebird/src/main/antlr4/imports/firebird/FirebirdKeyword.g4
@@ -507,6 +507,10 @@ NULLIF
     : N U L L I F
     ;
 
+NULLS
+    : N U L L S
+    ;
+
 NUMERIC
     : N U M E R I C
     ;
diff --git 
a/parser/sql/engine/dialect/firebird/src/main/java/org/apache/shardingsphere/sql/parser/engine/firebird/visitor/statement/FirebirdStatementVisitor.java
 
b/parser/sql/engine/dialect/firebird/src/main/java/org/apache/shardingsphere/sql/parser/engine/firebird/visitor/statement/FirebirdStatementVisitor.java
index d03f6c83248..17cd8598154 100644
--- 
a/parser/sql/engine/dialect/firebird/src/main/java/org/apache/shardingsphere/sql/parser/engine/firebird/visitor/statement/FirebirdStatementVisitor.java
+++ 
b/parser/sql/engine/dialect/firebird/src/main/java/org/apache/shardingsphere/sql/parser/engine/firebird/visitor/statement/FirebirdStatementVisitor.java
@@ -24,6 +24,7 @@ import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.misc.Interval;
 import org.antlr.v4.runtime.tree.TerminalNode;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.enums.NullsOrderType;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.sql.parser.api.ASTNode;
 import 
org.apache.shardingsphere.sql.parser.autogen.FirebirdStatementBaseVisitor;
@@ -116,6 +117,7 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.Nu
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.OtherLiteralValue;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.literal.impl.StringLiteralValue;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.parametermarker.ParameterMarkerValue;
+import org.jspecify.annotations.Nullable;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -604,20 +606,29 @@ public abstract class FirebirdStatementVisitor extends 
FirebirdStatementBaseVisi
     @Override
     public final ASTNode visitOrderByItem(final OrderByItemContext ctx) {
         OrderDirection orderDirection = null == ctx.DESC() ? 
OrderDirection.ASC : OrderDirection.DESC;
+        NullsOrderType nullsOrderType = generateNullsOrderType(ctx);
         if (null != ctx.numberLiterals()) {
             return new 
IndexOrderByItemSegment(ctx.numberLiterals().getStart().getStartIndex(), 
ctx.numberLiterals().getStop().getStopIndex(),
-                    SQLUtils.getExactlyNumber(ctx.numberLiterals().getText(), 
10).intValue(), orderDirection, null);
+                    SQLUtils.getExactlyNumber(ctx.numberLiterals().getText(), 
10).intValue(), orderDirection, nullsOrderType);
         } else {
             ASTNode expr = visitExpr(ctx.expr());
             if (expr instanceof ColumnSegment) {
-                return new ColumnOrderByItemSegment((ColumnSegment) expr, 
orderDirection, null);
+                return new ColumnOrderByItemSegment((ColumnSegment) expr, 
orderDirection, nullsOrderType);
             } else {
                 return new 
ExpressionOrderByItemSegment(ctx.expr().getStart().getStartIndex(),
-                        ctx.expr().getStop().getStopIndex(), 
getOriginalText(ctx.expr()), orderDirection, null, (ExpressionSegment) expr);
+                        ctx.expr().getStop().getStopIndex(), 
getOriginalText(ctx.expr()), orderDirection, nullsOrderType, 
(ExpressionSegment) expr);
             }
         }
     }
     
+    @Nullable
+    private NullsOrderType generateNullsOrderType(final OrderByItemContext 
ctx) {
+        if (null == ctx.FIRST() && null == ctx.LAST()) {
+            return null;
+        }
+        return null == ctx.FIRST() ? NullsOrderType.LAST : 
NullsOrderType.FIRST;
+    }
+    
     @Override
     public final ASTNode visitDataType(final DataTypeContext ctx) {
         if (null != ctx.blobDataType()) {
diff --git a/test/it/parser/src/main/resources/case/dml/select-order-by.xml 
b/test/it/parser/src/main/resources/case/dml/select-order-by.xml
index c59feb7dcaf..9a0dde4b60f 100644
--- a/test/it/parser/src/main/resources/case/dml/select-order-by.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-order-by.xml
@@ -218,6 +218,54 @@
         </order-by>
     </select>
 
+    <select sql-case-id="select_order_by_asc_nulls_last_firebird">
+        <from>
+            <simple-table name="t_order" alias="o" start-index="23" 
stop-index="31" />
+        </from>
+        <projections start-index="7" stop-index="16">
+            <column-projection name="order_id" start-index="7" stop-index="16">
+                <owner name="o" start-index="7" stop-index="7" />
+            </column-projection>
+        </projections>
+        <order-by>
+            <column-item name="order_id" start-index="42" stop-index="51" 
order-direction="ASC" nulls-order-type="LAST">
+                <owner name="o" start-index="42" stop-index="42" />
+            </column-item>
+        </order-by>
+    </select>
+
+    <select sql-case-id="select_order_by_desc_nulls_first_firebird">
+        <from>
+            <simple-table name="t_order" alias="o" start-index="23" 
stop-index="31" />
+        </from>
+        <projections start-index="7" stop-index="16">
+            <column-projection name="order_id" start-index="7" stop-index="16">
+                <owner name="o" start-index="7" stop-index="7" />
+            </column-projection>
+        </projections>
+        <order-by>
+            <column-item name="order_id" start-index="42" stop-index="51" 
order-direction="DESC" nulls-order-type="FIRST">
+                <owner name="o" start-index="42" stop-index="42" />
+            </column-item>
+        </order-by>
+    </select>
+
+    <select sql-case-id="select_order_by_nulls_column_firebird">
+        <from>
+            <simple-table name="t_order" alias="o" start-index="20" 
stop-index="28" />
+        </from>
+        <projections start-index="7" stop-index="13">
+            <column-projection name="nulls" start-index="7" stop-index="13">
+                <owner name="o" start-index="7" stop-index="7" />
+            </column-projection>
+        </projections>
+        <order-by>
+            <column-item name="nulls" start-index="39" stop-index="45" 
order-direction="ASC" nulls-order-type="FIRST">
+                <owner name="o" start-index="39" stop-index="39" />
+            </column-item>
+        </order-by>
+    </select>
+
     <select sql-case-id="select_order_by_with_multiple_stars">
         <from>
             <simple-table name="t_order" alias="o" start-index="29" 
stop-index="37" />
diff --git 
a/test/it/parser/src/main/resources/sql/supported/dml/select-order-by.xml 
b/test/it/parser/src/main/resources/sql/supported/dml/select-order-by.xml
index 3d64efc9dfc..f38cce0a85b 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select-order-by.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select-order-by.xml
@@ -24,6 +24,9 @@
     <sql-case id="select_order_by_with_date" value="SELECT i.* FROM t_order o, 
t_order_item i WHERE o.order_id = i.order_id AND o.status = 'init' ORDER BY 
i.creation_date DESC, o.order_id DESC, i.item_id" />
     <sql-case id="select_order_by_for_nulls_first" value="SELECT o.order_id AS 
gen_order_id_ FROM t_order o ORDER BY o.order_id NULLS FIRST" 
db-types="PostgreSQL,openGauss,Oracle" />
     <sql-case id="select_order_by_for_nulls_last" value="SELECT o.order_id AS 
gen_order_id_ FROM t_order o ORDER BY o.order_id ASC NULLS LAST" 
db-types="PostgreSQL,openGauss,Oracle" />
+    <sql-case id="select_order_by_asc_nulls_last_firebird" value="SELECT 
o.order_id FROM t_order o ORDER BY o.order_id ASC NULLS LAST" 
db-types="Firebird" />
+    <sql-case id="select_order_by_desc_nulls_first_firebird" value="SELECT 
o.order_id FROM t_order o ORDER BY o.order_id DESC NULLS FIRST" 
db-types="Firebird" />
+    <sql-case id="select_order_by_nulls_column_firebird" value="SELECT o.nulls 
FROM t_order o ORDER BY o.nulls NULLS FIRST" db-types="Firebird" />
     <sql-case id="select_order_by_with_multiple_stars" value="SELECT *, 
order_id, o.* FROM t_order o ORDER BY o.order_id" db-types="MySQL, SQLServer, 
PostgreSQL,openGauss" />
     <sql-case id="select_order_by_desc" value="SELECT * FROM employees WHERE 
job_id = 'PU_CLERK' ORDER BY salary DESC" db-types="Oracle" />
     <sql-case id="select_order_by_asc_desc" value="SELECT salary, last_name 
FROM employees ORDER BY salary ASC, last_name DESC" db-types="Oracle" />

Reply via email to