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 5f970d1404e Fix COUNT(*) handling for Firebird (#37494)
5f970d1404e is described below

commit 5f970d1404e23c5ee23ba44053f3c8049df5d778
Author: Maxim Sentyabrskiy <[email protected]>
AuthorDate: Thu Dec 25 07:47:25 2025 +0300

    Fix COUNT(*) handling for Firebird (#37494)
    
    * fix COUNT(*) realisation
    
    * fix COUNT(*) without alias
    
    * fixes
---
 distribution/bom/pom.xml                           |  5 ++
 .../binder/dialect}/firebird/pom.xml               |  7 +--
 .../FirebirdProjectionIdentifierExtractor.java     | 54 ++++++++++++++++
 ....extractor.DialectProjectionIdentifierExtractor | 18 ++++++
 .../FirebirdProjectionIdentifierExtractorTest.java | 72 ++++++++++++++++++++++
 infra/binder/dialect/pom.xml                       |  1 +
 jdbc-dialect/firebird/pom.xml                      |  6 ++
 proxy/dialect/firebird/pom.xml                     |  6 ++
 .../FirebirdPrepareStatementCommandExecutor.java   |  4 +-
 ...irebirdPrepareStatementCommandExecutorTest.java | 39 +++++++++++-
 10 files changed, 206 insertions(+), 6 deletions(-)

diff --git a/distribution/bom/pom.xml b/distribution/bom/pom.xml
index 878ce911324..a5c29fe7723 100644
--- a/distribution/bom/pom.xml
+++ b/distribution/bom/pom.xml
@@ -195,6 +195,11 @@
                 <artifactId>shardingsphere-infra-binder-opengauss</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.shardingsphere</groupId>
+                <artifactId>shardingsphere-infra-binder-firebird</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.shardingsphere</groupId>
                 <artifactId>shardingsphere-infra-checker</artifactId>
diff --git a/jdbc-dialect/firebird/pom.xml 
b/infra/binder/dialect/firebird/pom.xml
similarity index 86%
copy from jdbc-dialect/firebird/pom.xml
copy to infra/binder/dialect/firebird/pom.xml
index 0c577f9ec43..81ed0a9dc1b 100644
--- a/jdbc-dialect/firebird/pom.xml
+++ b/infra/binder/dialect/firebird/pom.xml
@@ -20,18 +20,17 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.shardingsphere</groupId>
-        <artifactId>shardingsphere-jdbc-dialect</artifactId>
+        <artifactId>shardingsphere-infra-binder-dialect</artifactId>
         <version>5.5.3-SNAPSHOT</version>
     </parent>
-    <artifactId>shardingsphere-jdbc-dialect-firebird</artifactId>
+    <artifactId>shardingsphere-infra-binder-firebird</artifactId>
     <name>${project.artifactId}</name>
     
     <dependencies>
         <dependency>
             <groupId>org.apache.shardingsphere</groupId>
-            <artifactId>shardingsphere-parser-sql-engine-firebird</artifactId>
+            <artifactId>shardingsphere-infra-binder-core</artifactId>
             <version>${project.version}</version>
-            <scope>runtime</scope>
         </dependency>
     </dependencies>
 </project>
diff --git 
a/infra/binder/dialect/firebird/src/main/java/org/apache/shardingsphere/infra/binder/firebird/FirebirdProjectionIdentifierExtractor.java
 
b/infra/binder/dialect/firebird/src/main/java/org/apache/shardingsphere/infra/binder/firebird/FirebirdProjectionIdentifierExtractor.java
new file mode 100644
index 00000000000..800c91e17f2
--- /dev/null
+++ 
b/infra/binder/dialect/firebird/src/main/java/org/apache/shardingsphere/infra/binder/firebird/FirebirdProjectionIdentifierExtractor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.firebird;
+
+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.item.SubqueryProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+
+/**
+ * Projection identifier extractor for Firebird.
+ */
+public final class FirebirdProjectionIdentifierExtractor implements 
DialectProjectionIdentifierExtractor {
+    
+    @Override
+    public String getIdentifierValue(final IdentifierValue identifierValue) {
+        return identifierValue.getValue();
+    }
+    
+    @Override
+    public String getColumnNameFromFunction(final String functionName, final 
String functionExpression) {
+        return functionName;
+    }
+    
+    @Override
+    public String getColumnNameFromExpression(final ExpressionSegment 
expressionSegment) {
+        return expressionSegment.getText();
+    }
+    
+    @Override
+    public String getColumnNameFromSubquery(final SubqueryProjectionSegment 
subquerySegment) {
+        return subquerySegment.getText();
+    }
+    
+    @Override
+    public String getDatabaseType() {
+        return "Firebird";
+    }
+}
diff --git 
a/infra/binder/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.binder.context.segment.select.projection.extractor.DialectProjectionIdentifierExtractor
 
b/infra/binder/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.binder.context.segment.select.projection.extractor.DialectProjectionIdentifierExtractor
new file mode 100644
index 00000000000..4dd472289ba
--- /dev/null
+++ 
b/infra/binder/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.binder.context.segment.select.projection.extractor.DialectProjectionIdentifierExtractor
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.shardingsphere.infra.binder.firebird.FirebirdProjectionIdentifierExtractor
diff --git 
a/infra/binder/dialect/firebird/src/test/java/org/apache/shardingsphere/infra/binder/firebird/FirebirdProjectionIdentifierExtractorTest.java
 
b/infra/binder/dialect/firebird/src/test/java/org/apache/shardingsphere/infra/binder/firebird/FirebirdProjectionIdentifierExtractorTest.java
new file mode 100644
index 00000000000..a5e57829842
--- /dev/null
+++ 
b/infra/binder/dialect/firebird/src/test/java/org/apache/shardingsphere/infra/binder/firebird/FirebirdProjectionIdentifierExtractorTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.firebird;
+
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.extractor.DialectProjectionIdentifierExtractor;
+import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.AggregationProjection;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import 
org.apache.shardingsphere.sql.parser.statement.core.enums.AggregationType;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class FirebirdProjectionIdentifierExtractorTest {
+    
+    private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "Firebird");
+    
+    private final DialectProjectionIdentifierExtractor extractor = 
DatabaseTypedSPILoader.getService(DialectProjectionIdentifierExtractor.class, 
databaseType);
+    
+    @Test
+    void assertGetIdentifierValue() {
+        assertThat(extractor.getIdentifierValue(new IdentifierValue("value")), 
is("value"));
+    }
+    
+    @Test
+    void assertGetColumnNameFromFunction() {
+        assertThat(extractor.getColumnNameFromFunction("COUNT", "COUNT(*)"), 
is("COUNT"));
+    }
+    
+    @Test
+    void assertGetColumnNameFromExpression() {
+        ExpressionSegment expressionSegment = mock(ExpressionSegment.class);
+        when(expressionSegment.getText()).thenReturn("expr");
+        assertThat(extractor.getColumnNameFromExpression(expressionSegment), 
is("expr"));
+    }
+    
+    @Test
+    void assertGetColumnNameFromSubquery() {
+        SubqueryProjectionSegment subquerySegment = 
mock(SubqueryProjectionSegment.class);
+        when(subquerySegment.getText()).thenReturn("sub");
+        assertThat(extractor.getColumnNameFromSubquery(subquerySegment), 
is("sub"));
+    }
+    
+    @Test
+    void assertAggregationProjectionColumnLabelWithoutAlias() {
+        AggregationProjection projection = new 
AggregationProjection(AggregationType.COUNT, new 
AggregationProjectionSegment(0, 0, AggregationType.COUNT, "COUNT(*)"), null, 
databaseType);
+        assertThat(projection.getColumnLabel(), is("COUNT"));
+    }
+}
diff --git a/infra/binder/dialect/pom.xml b/infra/binder/dialect/pom.xml
index ac4fdba1ce5..e0c12d58475 100644
--- a/infra/binder/dialect/pom.xml
+++ b/infra/binder/dialect/pom.xml
@@ -33,5 +33,6 @@
         <module>oracle</module>
         <module>sqlserver</module>
         <module>opengauss</module>
+        <module>firebird</module>
     </modules>
 </project>
diff --git a/jdbc-dialect/firebird/pom.xml b/jdbc-dialect/firebird/pom.xml
index 0c577f9ec43..d6fe9cead16 100644
--- a/jdbc-dialect/firebird/pom.xml
+++ b/jdbc-dialect/firebird/pom.xml
@@ -33,5 +33,11 @@
             <version>${project.version}</version>
             <scope>runtime</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-infra-binder-firebird</artifactId>
+            <version>${project.version}</version>
+            <scope>runtime</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/proxy/dialect/firebird/pom.xml b/proxy/dialect/firebird/pom.xml
index 38bff61ce2a..6a22757f44d 100644
--- a/proxy/dialect/firebird/pom.xml
+++ b/proxy/dialect/firebird/pom.xml
@@ -40,6 +40,12 @@
             <version>${project.version}</version>
             <scope>runtime</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-infra-binder-firebird</artifactId>
+            <version>${project.version}</version>
+            <scope>runtime</scope>
+        </dependency>
         
         <dependency>
             <groupId>org.apache.shardingsphere</groupId>
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutor.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutor.java
index e80c774d146..7a425dd11d8 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutor.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutor.java
@@ -89,6 +89,7 @@ import java.util.Collections;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.OptionalInt;
+import java.util.Locale;
 
 /**
  * Firebird prepare transaction command executor.
@@ -413,13 +414,14 @@ public final class 
FirebirdPrepareStatementCommandExecutor implements CommandExe
     
     private int getFunctionType(final String functionName) {
         // TODO add proper coalesce and other conditional functions return 
types
-        switch (functionName) {
+        switch (functionName.toLowerCase(Locale.ENGLISH)) {
             case "substring":
             case "current_role":
             case "current_user":
             case "coalesce":
                 return Types.VARCHAR;
             case "gen_id":
+            case "count":
                 return Types.BIGINT;
             case "current_timestamp":
                 return Types.TIMESTAMP;
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutorTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutorTest.java
index 77ca09d0714..aa517dbe1c1 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutorTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutorTest.java
@@ -18,11 +18,14 @@
 package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.prepare;
 
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.FirebirdBinaryColumnType;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.info.type.sql.FirebirdSQLInfoPacketType;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.info.type.sql.FirebirdSQLInfoReturnValue;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.prepare.FirebirdPrepareStatementPacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.prepare.FirebirdPrepareStatementReturnPacket;
+import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.prepare.FirebirdReturnColumnPacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdGenericResponsePacket;
+import 
org.apache.shardingsphere.database.protocol.firebird.payload.FirebirdPacketPayload;
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
 import 
org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
@@ -31,9 +34,13 @@ import 
org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
 import 
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereStatistics;
+import org.apache.shardingsphere.infra.metadata.user.Grantee;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
 import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 import org.apache.shardingsphere.parser.config.SQLParserRuleConfiguration;
 import org.apache.shardingsphere.parser.rule.SQLParserRule;
@@ -49,9 +56,11 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Answers;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 
+import java.sql.Types;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Properties;
@@ -59,6 +68,8 @@ import java.util.Properties;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(AutoMockExtension.class)
@@ -76,8 +87,10 @@ class FirebirdPrepareStatementCommandExecutorTest {
     
     @BeforeEach
     void setUp() {
+        ConnectionContext connectionContext = new 
ConnectionContext(Collections::emptySet, new Grantee("foo_user"));
         
when(connectionSession.getServerPreparedStatementRegistry()).thenReturn(new 
ServerPreparedStatementRegistry());
         when(connectionSession.getCurrentDatabaseName()).thenReturn("foo_db");
+        
when(connectionSession.getConnectionContext()).thenReturn(connectionContext);
         when(packet.getSQL()).thenReturn("SELECT 1");
         when(packet.getHintValueContext()).thenReturn(new HintValueContext());
         when(packet.isValidStatementHandle()).thenReturn(true);
@@ -90,7 +103,9 @@ class FirebirdPrepareStatementCommandExecutorTest {
     private MetaDataContexts createMetaDataContexts() {
         SQLParserRule parserRule = new SQLParserRule(new 
SQLParserRuleConfiguration(new CacheOption(128, 1024L), new CacheOption(128, 
1024L)));
         RuleMetaData globalRuleMetaData = new 
RuleMetaData(Collections.singleton(parserRule));
-        ShardingSphereSchema schema = new ShardingSphereSchema("foo_db", 
Collections.emptyList(), Collections.emptyList());
+        ShardingSphereColumn column = new ShardingSphereColumn("id", 
Types.INTEGER, false, false, true, true, false, true);
+        ShardingSphereTable table = new ShardingSphereTable("foo_tbl", 
Collections.singleton(column), Collections.emptyList(), 
Collections.emptyList());
+        ShardingSphereSchema schema = new ShardingSphereSchema("foo_db", 
Collections.singleton(table), Collections.emptyList());
         ShardingSphereDatabase database = new ShardingSphereDatabase(
                 "foo_db", databaseType, new 
ResourceMetaData(Collections.emptyMap()), new 
RuleMetaData(Collections.emptyList()), Collections.singleton(schema));
         ShardingSphereMetaData metaData = new ShardingSphereMetaData(
@@ -109,4 +124,26 @@ class FirebirdPrepareStatementCommandExecutorTest {
         assertThat(preparedStatement.getSql(), is("SELECT 1"));
         assertThat(preparedStatement.getSqlStatementContext(), 
isA(SelectStatementContext.class));
     }
+    
+    @Test
+    void assertDescribeCountReturnsBigintType() {
+        when(packet.getSQL()).thenReturn("SELECT COUNT(*) FROM foo_tbl");
+        when(packet.nextItem()).thenReturn(true, true, true, true, true, 
false);
+        when(packet.getCurrentItem()).thenReturn(
+                FirebirdSQLInfoPacketType.STMT_TYPE,
+                FirebirdSQLInfoPacketType.SELECT,
+                FirebirdSQLInfoPacketType.TYPE,
+                FirebirdSQLInfoPacketType.TYPE,
+                FirebirdSQLInfoPacketType.DESCRIBE_END,
+                FirebirdSQLInfoPacketType.DESCRIBE_END);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        FirebirdGenericResponsePacket responsePacket = 
(FirebirdGenericResponsePacket) actual.iterator().next();
+        FirebirdPrepareStatementReturnPacket returnPacket = 
(FirebirdPrepareStatementReturnPacket) responsePacket.getData();
+        assertThat(returnPacket.getDescribeSelect().size(), is(1));
+        FirebirdPacketPayload payload = mock(FirebirdPacketPayload.class, 
Mockito.RETURNS_DEEP_STUBS);
+        FirebirdReturnColumnPacket columnPacket = 
returnPacket.getDescribeSelect().get(0);
+        columnPacket.write(payload);
+        verify(payload).writeInt4LE(FirebirdBinaryColumnType.INT64.getValue() 
+ 1);
+    }
 }

Reply via email to