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 1e890783241 Align generated query rows with metadata (#38826)
1e890783241 is described below

commit 1e890783241fe4de1b781d3feb945b687d526205
Author: Liang Zhang <[email protected]>
AuthorDate: Sat Jun 6 17:36:21 2026 +0800

    Align generated query rows with metadata (#38826)
    
    Ensure generated admin query results build metadata and row data from the 
same ordered column labels, filling missing row cells instead of exposing 
shorter rows. Reject unsupported MySQL no-FROM sane result projections rather 
than silently dropping them, and replace the reflective connector symptom test 
with producer-side regression coverage.
---
 .../admin/executor/DatabaseMetaDataExecutor.java   | 20 ++++--
 .../StandardDatabaseProxyConnectorTest.java        | 59 ---------------
 .../executor/DatabaseMetaDataExecutorTest.java     | 84 +++++++++++++++++-----
 .../sane/MySQLDialectSaneQueryResultEngine.java    | 19 ++---
 .../MySQLDialectSaneQueryResultEngineTest.java     | 13 +++-
 ...LSelectWithoutFromAdminExecutorFactoryTest.java | 15 +++-
 6 files changed, 115 insertions(+), 95 deletions(-)

diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/DatabaseMetaDataExecutor.java
 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/DatabaseMetaDataExecutor.java
index 3baae3fad10..2d3766bbacb 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/DatabaseMetaDataExecutor.java
+++ 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/DatabaseMetaDataExecutor.java
@@ -139,17 +139,25 @@ public class DatabaseMetaDataExecutor implements 
DatabaseAdminQueryExecutor {
     }
     
     private RawQueryResultMetaData createQueryResultMetaData() {
-        if (rows.isEmpty() && !labels.isEmpty()) {
-            List<RawQueryResultColumnMetaData> columns = 
labels.stream().map(each -> new RawQueryResultColumnMetaData("", each, each, 
Types.VARCHAR, "VARCHAR", 20, 0)).collect(Collectors.toList());
-            return new RawQueryResultMetaData(columns);
-        }
-        List<RawQueryResultColumnMetaData> columns = 
rows.stream().flatMap(each -> 
each.keySet().stream()).collect(Collectors.toCollection(LinkedHashSet::new))
+        Collection<String> columnLabels = rows.isEmpty() && !labels.isEmpty()
+                ? labels
+                : rows.stream().flatMap(each -> 
each.keySet().stream()).collect(Collectors.toCollection(LinkedHashSet::new));
+        List<RawQueryResultColumnMetaData> columns = columnLabels
                 .stream().map(each -> new RawQueryResultColumnMetaData("", 
each, each, Types.VARCHAR, "VARCHAR", 20, 0)).collect(Collectors.toList());
         return new RawQueryResultMetaData(columns);
     }
     
     private MergedResult createMergedResult() {
-        List<MemoryQueryResultDataRow> resultDataRows = rows.stream().map(each 
-> new MemoryQueryResultDataRow(new 
LinkedList<>(each.values()))).collect(Collectors.toList());
+        Collection<String> columnLabels = rows.isEmpty() && !labels.isEmpty()
+                ? labels
+                : rows.stream().flatMap(each -> 
each.keySet().stream()).collect(Collectors.toCollection(LinkedHashSet::new));
+        List<MemoryQueryResultDataRow> resultDataRows = rows.stream().map(each 
-> {
+            List<Object> rowData = new LinkedList<>();
+            for (String columnLabel : columnLabels) {
+                rowData.add(each.getOrDefault(columnLabel, ""));
+            }
+            return new MemoryQueryResultDataRow(rowData);
+        }).collect(Collectors.toList());
         return new TransparentMergedResult(new 
RawMemoryQueryResult(queryResultMetaData, resultDataRows));
     }
 }
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
index bf8de9a48cc..c1151dd71eb 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
@@ -23,7 +23,6 @@ import 
org.apache.shardingsphere.database.connector.core.metadata.database.metad
 import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegistry;
-import 
org.apache.shardingsphere.driver.jdbc.core.resultset.ShardingSphereResultSetMetaData;
 import 
org.apache.shardingsphere.infra.binder.context.segment.insert.keygen.GeneratedKeyContext;
 import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.Projection;
 import 
org.apache.shardingsphere.infra.binder.context.segment.select.projection.ProjectionsContext;
@@ -45,20 +44,13 @@ import 
org.apache.shardingsphere.infra.executor.sql.prepare.driver.jdbc.JDBCDriv
 import org.apache.shardingsphere.infra.hint.HintValueContext;
 import org.apache.shardingsphere.infra.merge.MergeEngine;
 import org.apache.shardingsphere.infra.merge.result.MergedResult;
-import 
org.apache.shardingsphere.infra.merge.result.impl.memory.MemoryMergedResult;
-import 
org.apache.shardingsphere.infra.merge.result.impl.memory.MemoryQueryResultRow;
 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.ShardingSphereIndex;
-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.database.schema.util.SystemSchemaUtils;
 import 
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereStatistics;
 import 
org.apache.shardingsphere.infra.metadata.statistics.builder.ShardingSphereStatisticsFactory;
-import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
 import 
org.apache.shardingsphere.infra.rule.attribute.datanode.DataNodeRuleAttribute;
 import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
 import 
org.apache.shardingsphere.infra.session.connection.cursor.CursorConnectionContext;
@@ -78,7 +70,6 @@ import 
org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
 import 
org.apache.shardingsphere.proxy.backend.response.header.query.QueryHeaderBuilder;
-import 
org.apache.shardingsphere.proxy.backend.response.header.query.QueryHeaderBuilderEngine;
 import 
org.apache.shardingsphere.proxy.backend.response.header.query.QueryResponseHeader;
 import 
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
 import org.apache.shardingsphere.sharding.rule.ShardingRule;
@@ -109,17 +100,14 @@ import org.mockito.internal.configuration.plugins.Plugins;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 
-import java.lang.reflect.Field;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Statement;
-import java.sql.Types;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.stream.Collectors;
@@ -199,37 +187,6 @@ class StandardDatabaseProxyConnectorTest {
         return result;
     }
     
-    @Test
-    void assertBinaryProtocolQueryHeader() throws SQLException, 
NoSuchFieldException, IllegalAccessException {
-        SQLStatementContext sqlStatementContext = 
mock(SQLStatementContext.class, RETURNS_DEEP_STUBS);
-        
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
-        
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(databaseType);
-        DatabaseProxyConnector engine = 
createDatabaseProxyConnector(JDBCDriverType.PREPARED_STATEMENT, 
createQueryContext(sqlStatementContext, mockDatabase()));
-        Field queryHeadersField = 
StandardDatabaseProxyConnector.class.getDeclaredField("queryHeaders");
-        ShardingSphereDatabase database = createDatabaseMetaData();
-        try (MockedStatic<DatabaseTypedSPILoader> spiLoader = 
mockStatic(DatabaseTypedSPILoader.class)) {
-            spiLoader.when(() -> 
DatabaseTypedSPILoader.getService(QueryHeaderBuilder.class, 
databaseType)).thenReturn(new QueryHeaderBuilderFixture());
-            Plugins.getMemberAccessor().set(queryHeadersField, engine, 
Collections.singletonList(new 
QueryHeaderBuilderEngine(databaseType).build(createResultSetMetaData(), 
database, 1)));
-            Field mergedResultField = 
StandardDatabaseProxyConnector.class.getDeclaredField("mergedResult");
-            Plugins.getMemberAccessor().set(mergedResultField, engine, new 
MemoryMergedResult<ShardingSphereRule>(null, null, null, 
Collections.emptyList()) {
-                
-                @Override
-                protected List<MemoryQueryResultRow> init(final 
ShardingSphereRule rule, final ShardingSphereSchema schema,
-                                                          final 
SQLStatementContext sqlStatementContext, final List<QueryResult> queryResults) {
-                    return 
Collections.singletonList(mock(MemoryQueryResultRow.class));
-                }
-            });
-            Exception ex = null;
-            try {
-                engine.getRowData();
-            } catch (final SQLException | IndexOutOfBoundsException exception) 
{
-                ex = exception;
-            } finally {
-                assertFalse(ex instanceof IndexOutOfBoundsException);
-            }
-        }
-    }
-    
     @Test
     void assertExecuteWithFederationMetaDataRefresh() throws SQLException {
         SQLStatementContext sqlStatementContext = 
createSQLStatementContext(new SQLStatement(databaseType));
@@ -707,22 +664,6 @@ class StandardDatabaseProxyConnectorTest {
         return new QueryContext(sqlStatementContext, "schemaName", 
Collections.emptyList(), new HintValueContext(), connectionContext, metaData);
     }
     
-    private ShardingSphereDatabase createDatabaseMetaData() {
-        ShardingSphereDatabase result = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
-        ShardingSphereColumn column = new ShardingSphereColumn("order_id", 
Types.INTEGER, true, false, false, true, false, false);
-        
when(result.getSchema("foo_db").getTable("t_logic_order")).thenReturn(new 
ShardingSphereTable(
-                "t_logic_order", Collections.singleton(column), 
Collections.singleton(new ShardingSphereIndex("order_id", 
Collections.emptyList(), false)), Collections.emptyList()));
-        
when(result.getRuleMetaData().getRules()).thenReturn(Collections.singleton(mock(ShardingRule.class)));
-        return result;
-    }
-    
-    private ShardingSphereResultSetMetaData createResultSetMetaData() throws 
SQLException {
-        ResultSetMetaData resultSetMetaData = mock(ResultSetMetaData.class);
-        when(resultSetMetaData.getColumnLabel(1)).thenReturn("order_id");
-        when(resultSetMetaData.getColumnName(1)).thenReturn("order_id");
-        return new ShardingSphereResultSetMetaData(resultSetMetaData, 
mock(ShardingSphereDatabase.class), null);
-    }
-    
     private ResponseHeader executeWithImplicitCommitCondition(final 
SQLStatement sqlStatement, final String transactionType, final boolean 
inTransaction,
                                                               final int 
executionUnitCount) throws SQLException {
         
when(databaseConnectionManager.getConnectionSession().isAutoCommit()).thenReturn(true);
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/DatabaseMetaDataExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/DatabaseMetaDataExecutorTest.java
index df11aa0c95b..d2b8b2e7721 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/DatabaseMetaDataExecutorTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/DatabaseMetaDataExecutorTest.java
@@ -28,6 +28,7 @@ import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaDa
 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.util.SystemSchemaUtils;
 import org.apache.shardingsphere.infra.metadata.user.Grantee;
+import org.apache.shardingsphere.infra.merge.result.MergedResult;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import org.apache.shardingsphere.test.infra.fixture.jdbc.MockedDataSource;
@@ -36,6 +37,8 @@ import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockS
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.Answers;
 import org.mockito.Mock;
 
@@ -46,6 +49,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -161,41 +165,89 @@ class DatabaseMetaDataExecutorTest {
         assertThat(executor.getQueryResultMetaData().getColumnCount(), is(0));
     }
     
-    @Test
-    void assertExecuteFillLabelsWhenRowsFilteredOut() throws SQLException {
-        Map<String, String> expectedResultSetMap = 
Collections.singletonMap("foo_column", "foo_value");
+    @ParameterizedTest(name = "{0}")
+    @ValueSource(strings = {"filtered_rows", "aligned_rows"})
+    void assertExecuteWithPreProcessedRows(final String scenario) throws 
SQLException {
+        if ("filtered_rows".equals(scenario)) {
+            Map<String, String> expectedResultSetMap = 
Collections.singletonMap("foo_column", "foo_value");
+            ShardingSphereDatabase database = new 
ShardingSphereDatabase("auth_db",
+                    databaseType, new 
ResourceMetaData(Collections.singletonMap("foo_ds", new 
MockedDataSource(mockConnection(expectedResultSetMap)))), mock(), 
Collections.emptyList(),
+                    new ConfigurationProperties(new Properties()));
+            DatabaseMetaDataExecutor executor = 
mock(DatabaseMetaDataExecutor.class, withSettings().useConstructor(
+                    "SELECT foo_column FROM foo_table", 
Collections.emptyList()).defaultAnswer(CALLS_REAL_METHODS));
+            doAnswer(invocation -> {
+                Map<String, Object> rows = invocation.getArgument(1);
+                rows.clear();
+                return null;
+            }).when(executor).preProcess(any(ShardingSphereDatabase.class), 
anyMap(), anyMap());
+            executor.execute(connectionSession, mockMetaData(database, 
Collections.singleton("auth_db")));
+            assertTrue(executor.getRows().isEmpty());
+            assertThat(executor.getQueryResultMetaData().getColumnCount(), 
is(1));
+            assertFalse(executor.getMergedResult().next());
+            return;
+        }
+        Map<String, String> firstResultSetMap = new LinkedHashMap<>(2, 1F);
+        firstResultSetMap.put("foo_column", "foo_value");
+        firstResultSetMap.put("bar_column", "bar_value");
+        Map<String, String> secondResultSetMap = new LinkedHashMap<>(2, 1F);
+        secondResultSetMap.put("foo_column", "second_foo_value");
+        secondResultSetMap.put("bar_column", "second_bar_value");
         ShardingSphereDatabase database = new ShardingSphereDatabase("auth_db",
-                databaseType, new 
ResourceMetaData(Collections.singletonMap("foo_ds", new 
MockedDataSource(mockConnection(expectedResultSetMap)))), mock(), 
Collections.emptyList(),
-                new ConfigurationProperties(new Properties()));
-        DatabaseMetaDataExecutor executor = 
mock(DatabaseMetaDataExecutor.class, withSettings().useConstructor(
-                "SELECT foo_column FROM foo_table", 
Collections.emptyList()).defaultAnswer(CALLS_REAL_METHODS));
+                databaseType, new 
ResourceMetaData(Collections.singletonMap("foo_ds", new 
MockedDataSource(mockConnection(firstResultSetMap, secondResultSetMap)))), 
mock(),
+                Collections.emptyList(), new ConfigurationProperties(new 
Properties()));
+        DatabaseMetaDataExecutor executor =
+                mock(DatabaseMetaDataExecutor.class, 
withSettings().useConstructor("SELECT foo_column, bar_column FROM foo_table", 
Collections.emptyList()).defaultAnswer(CALLS_REAL_METHODS));
         doAnswer(invocation -> {
             Map<String, Object> rows = invocation.getArgument(1);
-            rows.clear();
+            if ("foo_value".equals(rows.get("foo_column"))) {
+                rows.remove("bar_column");
+                rows.put("baz_column", "baz_value");
+            }
             return null;
         }).when(executor).preProcess(any(ShardingSphereDatabase.class), 
anyMap(), anyMap());
         executor.execute(connectionSession, mockMetaData(database, 
Collections.singleton("auth_db")));
-        assertTrue(executor.getRows().isEmpty());
-        assertThat(executor.getQueryResultMetaData().getColumnCount(), is(1));
-        assertFalse(executor.getMergedResult().next());
+        assertThat(executor.getQueryResultMetaData().getColumnCount(), is(3));
+        assertThat(executor.getQueryResultMetaData().getColumnLabel(1), 
is("foo_column"));
+        assertThat(executor.getQueryResultMetaData().getColumnLabel(2), 
is("baz_column"));
+        assertThat(executor.getQueryResultMetaData().getColumnLabel(3), 
is("bar_column"));
+        MergedResult actualMergedResult = executor.getMergedResult();
+        assertTrue(actualMergedResult.next());
+        assertThat(actualMergedResult.getValue(1, String.class), 
is("foo_value"));
+        assertThat(actualMergedResult.getValue(2, String.class), 
is("baz_value"));
+        assertThat(actualMergedResult.getValue(3, String.class), is(""));
+        assertTrue(actualMergedResult.next());
+        assertThat(actualMergedResult.getValue(1, String.class), 
is("second_foo_value"));
+        assertThat(actualMergedResult.getValue(2, String.class), is(""));
+        assertThat(actualMergedResult.getValue(3, String.class), 
is("second_bar_value"));
+        assertFalse(actualMergedResult.next());
     }
     
-    private Connection mockConnection(final Map<String, String> 
expectedResultSetMap) throws SQLException {
+    private Connection mockConnection(final Map<String, String> 
expectedResultSetMap, final Map<String, String>... 
additionalExpectedResultSetMaps) throws SQLException {
         Connection result = mock(Connection.class, RETURNS_DEEP_STUBS);
-        ResultSet resultSet = mockResultSet(expectedResultSetMap);
+        ResultSet resultSet = mockResultSet(expectedResultSetMap, 
additionalExpectedResultSetMaps);
         
when(result.prepareStatement(any(String.class)).executeQuery()).thenReturn(resultSet);
         return result;
     }
     
-    private ResultSet mockResultSet(final Map<String, String> 
expectedResultSetMap) throws SQLException {
+    private ResultSet mockResultSet(final Map<String, String> 
expectedResultSetMap, final Map<String, String>... 
additionalExpectedResultSetMaps) throws SQLException {
         ResultSet result = mock(ResultSet.class, RETURNS_DEEP_STUBS);
         List<String> keys = new ArrayList<>(expectedResultSetMap.keySet());
         for (int i = 0; i < keys.size(); i++) {
             when(result.getMetaData().getColumnName(i + 
1)).thenReturn(keys.get(i));
             when(result.getMetaData().getColumnLabel(i + 
1)).thenReturn(keys.get(i));
-            when(result.getString(i + 
1)).thenReturn(expectedResultSetMap.get(keys.get(i)));
+            List<String> columnValues = new 
ArrayList<>(additionalExpectedResultSetMaps.length + 1);
+            columnValues.add(expectedResultSetMap.get(keys.get(i)));
+            for (Map<String, String> each : additionalExpectedResultSetMaps) {
+                columnValues.add(each.get(keys.get(i)));
+            }
+            when(result.getString(i + 1)).thenReturn(columnValues.get(0), 
columnValues.subList(1, columnValues.size()).toArray(new String[0]));
+        }
+        List<Boolean> nextResults = new 
ArrayList<>(additionalExpectedResultSetMaps.length + 2);
+        for (int i = 0; i < additionalExpectedResultSetMaps.length + 1; i++) {
+            nextResults.add(true);
         }
-        when(result.next()).thenReturn(true, false);
+        nextResults.add(false);
+        when(result.next()).thenReturn(nextResults.get(0), 
nextResults.subList(1, nextResults.size()).toArray(new Boolean[0]));
         
when(result.getMetaData().getColumnCount()).thenReturn(expectedResultSetMap.size());
         return result;
     }
diff --git 
a/proxy/backend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/connector/sane/MySQLDialectSaneQueryResultEngine.java
 
b/proxy/backend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/connector/sane/MySQLDialectSaneQueryResultEngine.java
index 148ac2f4957..93fc676b0e6 100644
--- 
a/proxy/backend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/connector/sane/MySQLDialectSaneQueryResultEngine.java
+++ 
b/proxy/backend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/connector/sane/MySQLDialectSaneQueryResultEngine.java
@@ -72,16 +72,17 @@ public final class MySQLDialectSaneQueryResultEngine 
implements DialectSaneQuery
         List<RawQueryResultColumnMetaData> queryResultColumnMetaDataList = new 
ArrayList<>(sqlStatement.getProjections().getProjections().size());
         List<Object> data = new 
ArrayList<>(sqlStatement.getProjections().getProjections().size());
         for (ProjectionSegment each : 
sqlStatement.getProjections().getProjections()) {
-            if (each instanceof ExpressionProjectionSegment) {
-                ExpressionProjectionSegment expressionProjection = 
(ExpressionProjectionSegment) each;
-                String text = expressionProjection.getText();
-                String alias = 
expressionProjection.getAliasName().orElse(expressionProjection.getText());
-                
queryResultColumnMetaDataList.add(createRawQueryResultColumnMetaData(text, 
alias));
-                String value = expressionProjection.getExpr() instanceof 
VariableSegment
-                        ? 
MySQLSystemVariable.findSystemVariable(((VariableSegment) 
expressionProjection.getExpr()).getVariable()).map(MySQLSystemVariable::getDefaultValue).orElse("1")
-                        : "1";
-                data.add(value);
+            if (!(each instanceof ExpressionProjectionSegment)) {
+                return Optional.empty();
             }
+            ExpressionProjectionSegment expressionProjection = 
(ExpressionProjectionSegment) each;
+            String text = expressionProjection.getText();
+            String alias = 
expressionProjection.getAliasName().orElse(expressionProjection.getText());
+            
queryResultColumnMetaDataList.add(createRawQueryResultColumnMetaData(text, 
alias));
+            String value = expressionProjection.getExpr() instanceof 
VariableSegment
+                    ? 
MySQLSystemVariable.findSystemVariable(((VariableSegment) 
expressionProjection.getExpr()).getVariable()).map(MySQLSystemVariable::getDefaultValue).orElse("1")
+                    : "1";
+            data.add(value);
         }
         return queryResultColumnMetaDataList.isEmpty()
                 ? Optional.empty()
diff --git 
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/connector/sane/MySQLDialectSaneQueryResultEngineTest.java
 
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/connector/sane/MySQLDialectSaneQueryResultEngineTest.java
index a92c67cef5a..79f6c8371c2 100644
--- 
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/connector/sane/MySQLDialectSaneQueryResultEngineTest.java
+++ 
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/connector/sane/MySQLDialectSaneQueryResultEngineTest.java
@@ -25,6 +25,7 @@ import 
org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dal.VariableSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ExpressionProjectionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ShorthandProjectionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dal.SetStatement;
@@ -33,6 +34,8 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.Se
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 import 
org.apache.shardingsphere.sql.parser.statement.mysql.dal.show.MySQLShowOtherStatement;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import java.sql.SQLException;
 import java.util.Collections;
@@ -63,11 +66,17 @@ class MySQLDialectSaneQueryResultEngineTest {
         assertThat(new 
MySQLDialectSaneQueryResultEngine().getSaneQueryResult(selectStatement, new 
SQLException("")), is(Optional.empty()));
     }
     
-    @Test
-    void assertGetSaneQueryResultForSelectStatementWithoutFrom() {
+    @ParameterizedTest(name = "{0}")
+    @ValueSource(strings = {"expression_projections", 
"unsupported_projection"})
+    void assertGetSaneQueryResultForSelectStatementWithoutFrom(final String 
scenario) {
         SelectStatement selectStatement = 
SelectStatement.builder().databaseType(databaseType).projections(new 
ProjectionsSegment(0, 0)).build();
         selectStatement.getProjections().getProjections().add(new 
ExpressionProjectionSegment(0, 0, "@@session.transaction_read_only", new 
VariableSegment(0, 0, "transaction_read_only")));
         selectStatement.getProjections().getProjections().add(new 
ExpressionProjectionSegment(0, 0, "unknown_variable"));
+        if ("unsupported_projection".equals(scenario)) {
+            selectStatement.getProjections().getProjections().add(new 
ShorthandProjectionSegment(0, 0));
+            assertThat(new 
MySQLDialectSaneQueryResultEngine().getSaneQueryResult(selectStatement, new 
SQLException("")), is(Optional.empty()));
+            return;
+        }
         Optional<ExecuteResult> actual = new 
MySQLDialectSaneQueryResultEngine().getSaneQueryResult(selectStatement, new 
SQLException(""));
         assertTrue(actual.isPresent());
         assertThat(actual.get(), isA(RawMemoryQueryResult.class));
diff --git 
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactoryTest.java
 
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactoryTest.java
index 703818b54f2..232ab0bb988 100644
--- 
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactoryTest.java
+++ 
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactoryTest.java
@@ -35,9 +35,13 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.Proj
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.Optional;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -96,9 +100,14 @@ class MySQLSelectWithoutFromAdminExecutorFactoryTest {
         assertThat(actual.get(), isA(ShowCurrentDatabaseExecutor.class));
     }
     
-    @Test
-    void assertCreateNoResourceExecutorWhenEmptyResource() {
-        SelectStatement selectStatement = 
createSelectStatement(Collections.singletonList(new 
ExpressionProjectionSegment(0, 0, "other()")));
+    @ParameterizedTest(name = "{0}")
+    @ValueSource(ints = {1, 2})
+    void assertCreateNoResourceExecutorWhenEmptyResource(final int 
projectionCount) {
+        Collection<ProjectionSegment> projections = new LinkedList<>();
+        for (int i = 0; i < projectionCount; i++) {
+            projections.add(new ExpressionProjectionSegment(0, 0, "col" + i));
+        }
+        SelectStatement selectStatement = createSelectStatement(projections);
         ShardingSphereMetaData metaData = mock(ShardingSphereMetaData.class);
         when(metaData.getAllDatabases()).thenReturn(Collections.emptyList());
         Optional<DatabaseAdminExecutor> actual = 
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(

Reply via email to