diff --git a/proxy/backend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactory.java b/proxy/backend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactory.java index 470c536a13166..c544e89bee725 100644 --- a/proxy/backend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactory.java +++ b/proxy/backend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactory.java @@ -93,9 +93,17 @@ private static Optional mockExecutor(final SelectStatemen return Optional.of(new NoResourceShowExecutor(sqlStatement)); } boolean isUseDatabase = null != databaseName || sqlStatement.getFrom().isPresent(); + if (!isUseDatabase && hasMultipleProjections(sqlStatement)) { + return Optional.empty(); + } return isUseDatabase ? Optional.empty() : Optional.of(new UnicastResourceShowExecutor(sqlStatement, sql)); } + private static boolean hasMultipleProjections(final SelectStatement sqlStatement) { + Collection projections = sqlStatement.getProjections().getProjections(); + return projections.size() > 1; + } + private static boolean isEmptyResource(final ShardingSphereMetaData metaData) { Collection databases = metaData.getAllDatabases(); return databases.isEmpty() || databases.stream().noneMatch(ShardingSphereDatabase::containsDataSource); diff --git a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/MySQLAdminExecutorCreatorTest.java b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/MySQLAdminExecutorCreatorTest.java index 3a4b72859bc1f..7f69967391c98 100644 --- a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/MySQLAdminExecutorCreatorTest.java +++ b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/MySQLAdminExecutorCreatorTest.java @@ -73,6 +73,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Optional; @@ -405,4 +406,48 @@ void assertCreateWithDMLStatement() { Optional actual = new MySQLAdminExecutorCreator().create(sqlStatementContext, "DELETE FROM t", "", Collections.emptyList()); assertThat(actual, is(Optional.empty())); } + + @Test + void assertCreateWithNoFromAndMultiProjectionsSkipsAdmin() { + ResourceMetaData resourceMetaData = new ResourceMetaData(Collections.singletonMap("ds_0", new MockedDataSource())); + ShardingSphereDatabase database = new ShardingSphereDatabase("db_0", databaseType, resourceMetaData, mock(RuleMetaData.class), Collections.emptyList()); + initProxyContext(Collections.singleton(database)); + + SelectStatement selectStatement = mock(SelectStatement.class); + when(selectStatement.getFrom()).thenReturn(Optional.empty()); + ProjectionsSegment projectionsSegment = mock(ProjectionsSegment.class); + when(projectionsSegment.getProjections()).thenReturn(Arrays.asList( + new ExpressionProjectionSegment(0, 10, "database()"), + new ExpressionProjectionSegment(0, 10, "schema()"), + new ExpressionProjectionSegment(0, 10, "left(user(),instr(concat(user(),'@'),'@')-1)"))); + when(selectStatement.getProjections()).thenReturn(projectionsSegment); + SelectStatementContext sqlStatementContext = mock(SelectStatementContext.class); + when(sqlStatementContext.getSqlStatement()).thenReturn(selectStatement); + + Optional actual = + new MySQLAdminExecutorCreator().create(sqlStatementContext, "SELECT database(),schema(),left(user(),instr(concat(user(),'@'),'@')-1)", null, Collections.emptyList()); + assertThat(actual, is(Optional.empty())); + } + + @Test + void assertCreateWithMultiSystemVariablesUseSysVarExecutor() { + initProxyContext(Collections.emptyList()); + SelectStatement selectStatement = mock(SelectStatement.class); + when(selectStatement.getFrom()).thenReturn(Optional.empty()); + ProjectionsSegment projectionsSegment = mock(ProjectionsSegment.class); + VariableSegment v1 = new VariableSegment(0, 0, "version", "SESSION"); + VariableSegment v2 = new VariableSegment(0, 0, "transaction_isolation", "SESSION"); + when(projectionsSegment.getProjections()).thenReturn(Arrays.asList( + new ExpressionProjectionSegment(0, 10, "@@session.version", v1), + new ExpressionProjectionSegment(0, 10, "@@session.transaction_isolation", v2))); + when(selectStatement.getProjections()).thenReturn(projectionsSegment); + + SelectStatementContext sqlStatementContext = mock(SelectStatementContext.class); + when(sqlStatementContext.getSqlStatement()).thenReturn(selectStatement); + + Optional actual = new MySQLAdminExecutorCreator().create( + sqlStatementContext, "SELECT @@session.version, @@session.transaction_isolation", null, Collections.emptyList()); + assertTrue(actual.isPresent()); + assertThat(actual.get(), isA(MySQLSystemVariableQueryExecutor.class)); + } }