You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by ji...@apache.org on 2024/10/22 05:57:49 UTC
(shardingsphere) 13/43: Pick #32510, fix incorrect results for querying information_schema.SCHEMATA (#1)
This is an automated email from the ASF dual-hosted git repository.
jianglongtao pushed a commit to branch fix-33341
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
commit 2ad68571cea0715d7b071407dcd2370e3d6f217b
Author: Raigor <ra...@gmail.com>
AuthorDate: Fri Aug 16 11:46:44 2024 +0800
Pick #32510, fix incorrect results for querying information_schema.SCHEMATA (#1)
* Pick #32510, fix incorrect results for querying information_schema.SCHEMATA
* Fix SelectInformationSchemataExecutorTest
---
.../executor/AbstractDatabaseMetaDataExecutor.java | 18 ++----
.../SelectInformationSchemataExecutor.java | 73 +++++++++++++++-------
.../SelectInformationSchemataExecutorTest.java | 1 +
3 files changed, 58 insertions(+), 34 deletions(-)
diff --git a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/AbstractDatabaseMetaDataExecutor.java b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/AbstractDatabaseMetaDataExecutor.java
index b1884b4f2b4..33db8c08df3 100644
--- a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/AbstractDatabaseMetaDataExecutor.java
+++ b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/AbstractDatabaseMetaDataExecutor.java
@@ -70,7 +70,6 @@ public abstract class AbstractDatabaseMetaDataExecutor implements DatabaseAdminQ
public final void execute(final ConnectionSession connectionSession) throws SQLException {
Collection<String> databaseNames = getDatabaseNames(connectionSession);
for (String databaseName : databaseNames) {
- initDatabaseData(databaseName);
processMetaData(databaseName, resultSet -> handleResultSet(databaseName, resultSet));
}
postProcess();
@@ -82,9 +81,10 @@ public abstract class AbstractDatabaseMetaDataExecutor implements DatabaseAdminQ
private void handleResultSet(final String databaseName, final ResultSet resultSet) {
ResultSetMetaData metaData = resultSet.getMetaData();
while (resultSet.next()) {
- Map<String, Object> rowMap = new LinkedHashMap<>();
- Map<String, String> aliasMap = new LinkedHashMap<>();
- for (int i = 1; i < metaData.getColumnCount() + 1; i++) {
+ int columnCount = metaData.getColumnCount();
+ Map<String, Object> rowMap = new LinkedHashMap<>(columnCount, 1F);
+ Map<String, String> aliasMap = new LinkedHashMap<>(columnCount, 1F);
+ for (int i = 1; i < columnCount + 1; i++) {
aliasMap.put(metaData.getColumnName(i), metaData.getColumnLabel(i));
rowMap.put(metaData.getColumnLabel(i), resultSet.getString(i));
}
@@ -100,11 +100,9 @@ public abstract class AbstractDatabaseMetaDataExecutor implements DatabaseAdminQ
}
}
- protected abstract void initDatabaseData(String databaseName);
-
protected abstract Collection<String> getDatabaseNames(ConnectionSession connectionSession);
- protected abstract void preProcess(String databaseName, Map<String, Object> rows, Map<String, String> alias);
+ protected abstract void preProcess(String databaseName, Map<String, Object> rows, Map<String, String> alias) throws SQLException;
protected abstract void postProcess();
@@ -144,10 +142,6 @@ public abstract class AbstractDatabaseMetaDataExecutor implements DatabaseAdminQ
private final List<Object> parameters;
- @Override
- protected void initDatabaseData(final String databaseName) {
- }
-
@Override
protected Collection<String> getDatabaseNames(final ConnectionSession connectionSession) {
Optional<String> database = ProxyContext.getInstance().getAllDatabaseNames().stream().filter(each -> isAuthorized(each, connectionSession.getGrantee()))
@@ -175,7 +169,7 @@ public abstract class AbstractDatabaseMetaDataExecutor implements DatabaseAdminQ
}
@Override
- protected void preProcess(final String databaseName, final Map<String, Object> rows, final Map<String, String> alias) {
+ protected void preProcess(final String databaseName, final Map<String, Object> rows, final Map<String, String> alias) throws SQLException {
}
@Override
diff --git a/proxy/backend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/information/SelectInformationSchemataExecutor.java b/proxy/backend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/information/SelectInformationSchemataExecutor.java
index 2a1977247b2..22e32438fb6 100644
--- a/proxy/backend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/information/SelectInformationSchemataExecutor.java
+++ b/proxy/backend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/information/SelectInformationSchemataExecutor.java
@@ -18,6 +18,7 @@
package org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.information;
import org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
+import org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import org.apache.shardingsphere.proxy.backend.handler.admin.executor.AbstractDatabaseMetaDataExecutor;
import org.apache.shardingsphere.proxy.backend.handler.admin.executor.AbstractDatabaseMetaDataExecutor.DefaultDatabaseMetaDataExecutor;
@@ -27,7 +28,10 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.Projecti
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -84,7 +88,7 @@ public final class SelectInformationSchemataExecutor extends DefaultDatabaseMeta
@Override
protected Collection<String> getDatabaseNames(final ConnectionSession connectionSession) {
Collection<String> databaseNames = ProxyContext.getInstance().getAllDatabaseNames().stream().filter(each -> isAuthorized(each, connectionSession.getGrantee())).collect(Collectors.toList());
- SCHEMA_WITHOUT_DATA_SOURCE.addAll(databaseNames.stream().filter(each -> !AbstractDatabaseMetaDataExecutor.hasDataSource(each)).collect(Collectors.toSet()));
+ SCHEMA_WITHOUT_DATA_SOURCE.addAll(databaseNames.stream().filter(each -> !hasDataSource(each)).collect(Collectors.toSet()));
Collection<String> result = databaseNames.stream().filter(AbstractDatabaseMetaDataExecutor::hasDataSource).collect(Collectors.toList());
if (!SCHEMA_WITHOUT_DATA_SOURCE.isEmpty()) {
fillSchemasWithoutDataSource();
@@ -92,21 +96,6 @@ public final class SelectInformationSchemataExecutor extends DefaultDatabaseMeta
return result;
}
- @Override
- protected void preProcess(final String databaseName, final Map<String, Object> rows, final Map<String, String> alias) {
- ResourceMetaData resourceMetaData = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getDatabase(databaseName).getResourceMetaData();
- Collection<String> catalogs = resourceMetaData.getStorageUnits().keySet()
- .stream().map(each -> resourceMetaData.getStorageUnits().get(each).getCatalog()).collect(Collectors.toSet());
- schemaNameAlias = alias.getOrDefault(SCHEMA_NAME, "");
- String rowValue = rows.getOrDefault(schemaNameAlias, "").toString();
- queryDatabase = !rowValue.isEmpty();
- if (catalogs.contains(rowValue)) {
- rows.replace(schemaNameAlias, databaseName);
- } else {
- rows.clear();
- }
- }
-
private void fillSchemasWithoutDataSource() {
if (SCHEMA_WITHOUT_DATA_SOURCE.isEmpty()) {
return;
@@ -114,21 +103,61 @@ public final class SelectInformationSchemataExecutor extends DefaultDatabaseMeta
Map<String, String> defaultRowData = getTheDefaultRowData();
SCHEMA_WITHOUT_DATA_SOURCE.forEach(each -> {
Map<String, Object> row = new LinkedHashMap<>(defaultRowData);
- row.replace(SCHEMA_NAME, each);
+ row.replace(schemaNameAlias, each);
getRows().add(row);
});
SCHEMA_WITHOUT_DATA_SOURCE.clear();
}
private Map<String, String> getTheDefaultRowData() {
- Map<String, String> result;
Collection<ProjectionSegment> projections = sqlStatement.getProjections().getProjections();
if (projections.stream().anyMatch(ShorthandProjectionSegment.class::isInstance)) {
- result = Stream.of(CATALOG_NAME, SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME, SQL_PATH, DEFAULT_ENCRYPTION).collect(Collectors.toMap(each -> each, each -> ""));
- } else {
- result = projections.stream().map(each -> ((ColumnProjectionSegment) each).getColumn().getIdentifier())
- .map(each -> each.getValue().toUpperCase()).collect(Collectors.toMap(each -> each, each -> ""));
+ return Stream.of(CATALOG_NAME, SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME, SQL_PATH, DEFAULT_ENCRYPTION)
+ .collect(Collectors.toMap(each -> each, each -> "", (oldValue, currentValue) -> oldValue, LinkedHashMap::new));
+ }
+ return getDefaultRowsFromProjections(projections);
+ }
+
+ private Map<String, String> getDefaultRowsFromProjections(final Collection<ProjectionSegment> projections) {
+ Map<String, String> result = new LinkedHashMap<>(projections.size(), 1F);
+ for (ProjectionSegment each : projections) {
+ if (!each.getClass().isAssignableFrom(ColumnProjectionSegment.class)) {
+ continue;
+ }
+ if (((ColumnProjectionSegment) each).getAlias().isPresent()) {
+ String alias = ((ColumnProjectionSegment) each).getAlias().get().getValue();
+ if (((ColumnProjectionSegment) each).getColumn().getIdentifier().getValue().equalsIgnoreCase(SCHEMA_NAME)) {
+ schemaNameAlias = alias;
+ }
+ result.put(alias, "");
+ continue;
+ }
+ result.put(((ColumnProjectionSegment) each).getColumn().getIdentifier().getValue().toUpperCase(), "");
}
return result;
}
+
+ @Override
+ protected void preProcess(final String databaseName, final Map<String, Object> rows, final Map<String, String> alias) throws SQLException {
+ ResourceMetaData resourceMetaData = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getDatabase(databaseName).getResourceMetaData();
+ Collection<String> catalogs = getCatalogs(resourceMetaData);
+ schemaNameAlias = alias.getOrDefault(SCHEMA_NAME, "");
+ String rowValue = rows.getOrDefault(schemaNameAlias, "").toString();
+ queryDatabase = !rowValue.isEmpty();
+ if (catalogs.contains(rowValue)) {
+ rows.replace(schemaNameAlias, databaseName);
+ } else {
+ rows.clear();
+ }
+ }
+
+ private Collection<String> getCatalogs(final ResourceMetaData resourceMetaData) throws SQLException {
+ Optional<StorageUnit> storageUnit = resourceMetaData.getStorageUnits().values().stream().findFirst();
+ if (!storageUnit.isPresent()) {
+ return Collections.emptySet();
+ }
+ try (Connection connection = storageUnit.get().getDataSource().getConnection()) {
+ return Collections.singleton(connection.getCatalog());
+ }
+ }
}
diff --git a/proxy/backend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/information/SelectInformationSchemataExecutorTest.java b/proxy/backend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/information/SelectInformationSchemataExecutorTest.java
index 5fe08b1e86e..85d2d214f6b 100644
--- a/proxy/backend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/information/SelectInformationSchemataExecutorTest.java
+++ b/proxy/backend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/information/SelectInformationSchemataExecutorTest.java
@@ -186,6 +186,7 @@ class SelectInformationSchemataExecutorTest {
private Connection mockConnection(final Map<String, String> expectedResultSetMap) throws SQLException {
Connection result = mock(Connection.class, RETURNS_DEEP_STUBS);
when(result.getMetaData().getURL()).thenReturn("jdbc:mysql://localhost:3306/foo_ds");
+ when(result.getCatalog()).thenReturn("foo_ds");
ResultSet resultSet = mockResultSet(expectedResultSetMap);
when(result.prepareStatement(any(String.class)).executeQuery()).thenReturn(resultSet);
return result;