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 <[email protected]> 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;
