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 2021/11/07 08:23:08 UTC

[shardingsphere] branch master updated: Proxy support pg_database table of postgreSQL (#13482)

This is an automated email from the ASF dual-hosted git repository.

jianglongtao 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 1fcca09  Proxy support pg_database table of postgreSQL (#13482)
1fcca09 is described below

commit 1fcca0938f29d55df3e8be91db1a7fbf6797c4bb
Author: lanchengx <52...@users.noreply.github.com>
AuthorDate: Sun Nov 7 02:22:06 2021 -0600

    Proxy support pg_database table of postgreSQL (#13482)
    
    * Add test;
    
    * Support `pg_database` table of `postgreSQL`
    
    * Modify format.
---
 .../information => }/FunctionWithException.java    |   7 +-
 .../AbstractDatabaseMetadataExecutor.java}         |  80 +++++++++------
 .../MySQLInformationSchemaExecutorFactory.java     |   4 +-
 .../SelectInformationSchemataExecutor.java         |   9 +-
 .../postgresql/PostgreSQLAdminExecutorFactory.java |  67 ++++++++++++
 .../executor/SelectDatabaseExecutor.java           | 114 +++++++++++++++++++++
 ...ext.admin.executor.DatabaseAdminExecutorFactory |   1 +
 .../information/SelectInformationExecutorTest.java |   6 +-
 .../PostgreSQLAdminExecutorFactoryTest.java        |  51 +++++++++
 .../executor/SelectDatabaseExecutorTest.java}      |  94 ++++++++---------
 10 files changed, 337 insertions(+), 96 deletions(-)

diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/FunctionWithException.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/FunctionWithException.java
similarity index 82%
rename from shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/FunctionWithException.java
rename to shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/FunctionWithException.java
index fefd406..7d1a66c 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/FunctionWithException.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/FunctionWithException.java
@@ -15,20 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.information;
+package org.apache.shardingsphere.proxy.backend.text.admin;
 
 /**
  * FunctionWithException interface.
  */
 @FunctionalInterface
-public interface FunctionWithException<T, R, E extends Exception> {
+public interface FunctionWithException<T, E extends Exception> {
 
     /**
      * Apply function.
      *
      * @param t param
-     * @return return value
      * @throws E exception
      */
-    R apply(T t) throws E;
+    void apply(T t) throws E;
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/AbstractSelectInformationExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
similarity index 73%
rename from shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/AbstractSelectInformationExecutor.java
rename to shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
index 43b7ee0..34b7ad3 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/AbstractSelectInformationExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.information;
+package org.apache.shardingsphere.proxy.backend.text.admin.executor;
 
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
@@ -30,7 +30,7 @@ import org.apache.shardingsphere.infra.metadata.resource.ShardingSphereResource;
 import org.apache.shardingsphere.proxy.backend.communication.jdbc.connection.BackendConnection;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.proxy.backend.exception.DatabaseNotExistedException;
-import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminQueryExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.FunctionWithException;
 
 import javax.sql.DataSource;
 import java.sql.Connection;
@@ -49,9 +49,9 @@ import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
- * The abstract class of select information schema, used to define the template.
+ * The abstract class of database metadata, used to define the template.
  */
-public abstract class AbstractSelectInformationExecutor implements DatabaseAdminQueryExecutor {
+public abstract class AbstractDatabaseMetadataExecutor implements DatabaseAdminQueryExecutor {
     
     @Getter
     private QueryResultMetaData queryResultMetaData;
@@ -66,27 +66,29 @@ public abstract class AbstractSelectInformationExecutor implements DatabaseAdmin
     public final void execute(final BackendConnection backendConnection) throws SQLException {
         List<String> schemaNames = getSchemaNames();
         for (String schemaName : schemaNames) {
-            getSourceData(schemaName, resultSet -> {
-                while (resultSet.next()) {
-                    Map<String, Object> rowMap = new HashMap<>();
-                    Map<String, String> aliasMap = new HashMap<>();
-                    ResultSetMetaData metaData = resultSet.getMetaData();
-                    for (int i = 1; i < metaData.getColumnCount() + 1; i++) {
-                        aliasMap.put(metaData.getColumnName(i), metaData.getColumnLabel(i));
-                        rowMap.put(metaData.getColumnLabel(i), resultSet.getString(i));
-                    }
-                    rowPostProcessing(schemaName, rowMap, aliasMap);
-                    if (!rowMap.isEmpty()) {
-                        getRows().addFirst(rowMap);
-                    }
-                }
-                return null;
-            });
+            getSourceData(schemaName, resultSet -> handleResultSet(schemaName, resultSet));
         }
+        addDefaultRow(rows);
         queryResultMetaData = createQueryResultMetaData();
         mergedResult = createMergedResult();
     }
     
+    private void handleResultSet(final String schemaName, final ResultSet resultSet) throws SQLException {
+        while (resultSet.next()) {
+            Map<String, Object> rowMap = new HashMap<>();
+            Map<String, String> aliasMap = new HashMap<>();
+            ResultSetMetaData metaData = resultSet.getMetaData();
+            for (int i = 1; i < metaData.getColumnCount() + 1; i++) {
+                aliasMap.put(metaData.getColumnName(i), metaData.getColumnLabel(i));
+                rowMap.put(metaData.getColumnLabel(i), resultSet.getString(i));
+            }
+            rowPostProcessing(schemaName, rowMap, aliasMap);
+            if (!rowMap.isEmpty()) {
+                rows.addFirst(rowMap);
+            }
+        }
+    }
+    
     /**
      * Get the schema names as a condition for SQL execution.
      *
@@ -95,19 +97,26 @@ public abstract class AbstractSelectInformationExecutor implements DatabaseAdmin
     protected abstract List<String> getSchemaNames();
     
     /**
+     * Add default row data.
+     *
+     * @param rows row
+     */
+    protected abstract void addDefaultRow(LinkedList<Map<String, Object>> rows);
+    
+    /**
      * Get the source object of the row data.
      *
      * @param schemaName schema name
      * @param callback callback for processing source data of information_schema
      * @throws SQLException SQLException
      */
-    protected abstract void getSourceData(String schemaName, FunctionWithException<ResultSet, Void, SQLException> callback) throws SQLException;
+    protected abstract void getSourceData(String schemaName, FunctionWithException<ResultSet, SQLException> callback) throws SQLException;
     
     /**
      * Get the source object of the row data.
-     * 
-     *  @param schemaName schema name
-     * @param rowMap row 
+     *
+     * @param schemaName schema name
+     * @param rowMap row
      * @param aliasMap alias
      */
     protected abstract void rowPostProcessing(String schemaName, Map<String, Object> rowMap, Map<String, String> aliasMap);
@@ -135,15 +144,15 @@ public abstract class AbstractSelectInformationExecutor implements DatabaseAdmin
     }
     
     /**
-     * Default select information executor, execute sql directly in the database to obtain the result source data.
+     * Default database metadata executor, execute sql directly in the database to obtain the result source data.
      */
     @Slf4j
-    public static class DefaultSelectInformationExecutor extends AbstractSelectInformationExecutor {
+    public static class DefaultDatabaseMetadataExecutor extends AbstractDatabaseMetadataExecutor {
         
         @Getter
         private final String sql;
         
-        public DefaultSelectInformationExecutor(final String sql) {
+        public DefaultDatabaseMetadataExecutor(final String sql) {
             this.sql = sql;
         }
         
@@ -154,7 +163,7 @@ public abstract class AbstractSelectInformationExecutor implements DatabaseAdmin
          */
         @Override
         protected List<String> getSchemaNames() {
-            String schema = ProxyContext.getInstance().getAllSchemaNames().stream().filter(AbstractSelectInformationExecutor::hasDatasource).findFirst().orElseThrow(DatabaseNotExistedException::new);
+            String schema = ProxyContext.getInstance().getAllSchemaNames().stream().filter(AbstractDatabaseMetadataExecutor::hasDatasource).findFirst().orElseThrow(DatabaseNotExistedException::new);
             return Collections.singletonList(schema);
         }
         
@@ -165,7 +174,7 @@ public abstract class AbstractSelectInformationExecutor implements DatabaseAdmin
          * @throws SQLException SQLException
          */
         @Override
-        protected void getSourceData(final String schemaName, final FunctionWithException<ResultSet, Void, SQLException> callback) throws SQLException {
+        protected void getSourceData(final String schemaName, final FunctionWithException<ResultSet, SQLException> callback) throws SQLException {
             ShardingSphereResource resource = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData(schemaName).getResource();
             Optional<Entry<String, DataSource>> dataSourceEntry = resource.getDataSources().entrySet().stream().findFirst();
             log.info("Actual SQL: {} ::: {}", dataSourceEntry.orElseThrow(DatabaseNotExistedException::new).getKey(), sql);
@@ -177,13 +186,22 @@ public abstract class AbstractSelectInformationExecutor implements DatabaseAdmin
         
         /**
          * Custom processing.
-         * 
-         *  @param schemaName schema name
+         *
+         * @param schemaName schema name
          * @param rowMap row
          * @param aliasMap alias
          */
         @Override
         protected void rowPostProcessing(final String schemaName, final Map<String, Object> rowMap, final Map<String, String> aliasMap) {
         }
+    
+        /**
+         * Add default row data.
+         *
+         * @param rows row
+         */
+        @Override
+        protected void addDefaultRow(final LinkedList<Map<String, Object>> rows) {
+        }
     }
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLInformationSchemaExecutorFactory.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLInformationSchemaExecutorFactory.java
index b76c37a..844a82d 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLInformationSchemaExecutorFactory.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLInformationSchemaExecutorFactory.java
@@ -18,7 +18,7 @@
 package org.apache.shardingsphere.proxy.backend.text.admin.mysql;
 
 import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminQueryExecutor;
-import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.information.AbstractSelectInformationExecutor.DefaultSelectInformationExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.AbstractDatabaseMetadataExecutor.DefaultDatabaseMetadataExecutor;
 import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.information.SelectInformationSchemataExecutor;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
@@ -47,7 +47,7 @@ public final class MySQLInformationSchemaExecutorFactory {
         if (SCHEMATA_TABLE.equalsIgnoreCase(tableName)) {
             return new SelectInformationSchemataExecutor(sqlStatement, sql);
         } else if (DEFAULT_EXECUTOR_TABLES.contains(tableName.toUpperCase())) {
-            return new DefaultSelectInformationExecutor(sql);
+            return new DefaultDatabaseMetadataExecutor(sql);
         }
         throw new UnsupportedOperationException(String.format("unsupported table : `%s`", tableName));
     }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationSchemataExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationSchemataExecutor.java
index 06f84cc..0cd2d2d 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationSchemataExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationSchemataExecutor.java
@@ -19,7 +19,8 @@ package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.inform
 
 import org.apache.shardingsphere.infra.metadata.resource.ShardingSphereResource;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
-import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.information.AbstractSelectInformationExecutor.DefaultSelectInformationExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.AbstractDatabaseMetadataExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.AbstractDatabaseMetadataExecutor.DefaultDatabaseMetadataExecutor;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
@@ -38,7 +39,7 @@ import java.util.stream.Stream;
 /**
  * Schemata query executor, used to query the schemata table.
  */
-public final class SelectInformationSchemataExecutor extends DefaultSelectInformationExecutor {
+public final class SelectInformationSchemataExecutor extends DefaultDatabaseMetadataExecutor {
     
     public static final String SCHEMA_NAME = "SCHEMA_NAME";
     
@@ -64,8 +65,8 @@ public final class SelectInformationSchemataExecutor extends DefaultSelectInform
     @Override
     protected List<String> getSchemaNames() {
         Collection<String> schemaNames = ProxyContext.getInstance().getAllSchemaNames();
-        SCHEMA_WITHOUT_DATA_SOURCE.addAll(schemaNames.stream().filter(each -> !AbstractSelectInformationExecutor.hasDatasource(each)).collect(Collectors.toSet()));
-        List<String> result = schemaNames.stream().filter(AbstractSelectInformationExecutor::hasDatasource).collect(Collectors.toList());
+        SCHEMA_WITHOUT_DATA_SOURCE.addAll(schemaNames.stream().filter(each -> !AbstractDatabaseMetadataExecutor.hasDatasource(each)).collect(Collectors.toSet()));
+        List<String> result = schemaNames.stream().filter(AbstractDatabaseMetadataExecutor::hasDatasource).collect(Collectors.toList());
         if (!SCHEMA_WITHOUT_DATA_SOURCE.isEmpty()) {
             fillSchemasWithoutDatasource();
         }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/PostgreSQLAdminExecutorFactory.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/PostgreSQLAdminExecutorFactory.java
new file mode 100644
index 0000000..c6b6c96
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/PostgreSQLAdminExecutorFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.proxy.backend.text.admin.postgresql;
+
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutorFactory;
+import org.apache.shardingsphere.proxy.backend.text.admin.postgresql.executor.SelectDatabaseExecutor;
+import org.apache.shardingsphere.sql.parser.sql.common.extractor.TableExtractor;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * Admin executor factory for PostgreSQL.
+ */
+public final class PostgreSQLAdminExecutorFactory implements DatabaseAdminExecutorFactory {
+    
+    private static final String PG_DATABASE = "pg_database";
+    
+    @Override
+    public Optional<DatabaseAdminExecutor> newInstance(final SQLStatement sqlStatement) {
+        return Optional.empty();
+    }
+    
+    @Override
+    public Optional<DatabaseAdminExecutor> newInstance(final SQLStatement sqlStatement, final String sql) {
+        if (sqlStatement instanceof SelectStatement) {
+            Collection<String> selectedTableNames = getSelectedTableNames((SelectStatement) sqlStatement);
+            if (selectedTableNames.contains(PG_DATABASE)) {
+                return Optional.of(new SelectDatabaseExecutor((SelectStatement) sqlStatement, sql));
+            }
+        }
+        return Optional.empty();
+    }
+    
+    private Collection<String> getSelectedTableNames(final SelectStatement sqlStatement) {
+        TableExtractor extractor = new TableExtractor();
+        extractor.extractTablesFromSelect(sqlStatement);
+        return extractor.getTableContext().stream().filter(each -> each instanceof SimpleTableSegment)
+                .map(each -> ((SimpleTableSegment) each).getTableName().getIdentifier().getValue()).collect(Collectors.toCollection(LinkedList::new));
+    }
+    
+    @Override
+    public String getType() {
+        return "PostgreSQL";
+    }
+}
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectDatabaseExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectDatabaseExecutor.java
new file mode 100644
index 0000000..9e1d923
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectDatabaseExecutor.java
@@ -0,0 +1,114 @@
+/*
+ * 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.proxy.backend.text.admin.postgresql.executor;
+
+import org.apache.shardingsphere.infra.metadata.resource.ShardingSphereResource;
+import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.AbstractDatabaseMetadataExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.AbstractDatabaseMetadataExecutor.DefaultDatabaseMetadataExecutor;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Schemata query executor, used to query the schemata table.
+ */
+public final class SelectDatabaseExecutor extends DefaultDatabaseMetadataExecutor {
+    
+    private static final String DATABASE_NAME = "databasename";
+    
+    private final Set<String> columnNames = new LinkedHashSet<>();
+    
+    private final SelectStatement sqlStatement;
+    
+    private String databaseNameAlias = DATABASE_NAME;
+    
+    public SelectDatabaseExecutor(final SelectStatement sqlStatement, final String sql) {
+        super(sql);
+        this.sqlStatement = sqlStatement;
+    }
+    
+    @Override
+    protected void addDefaultRow(final LinkedList<Map<String, Object>> rows) {
+        LinkedList<String> schemaWithoutDataSource = ProxyContext.getInstance().getAllSchemaNames().stream()
+                .filter(each -> !hasDatasource(each)).collect(Collectors.toCollection(LinkedList::new));
+        schemaWithoutDataSource.forEach(each -> rows.addLast(getDefaultRowData(each)));
+    }
+    
+    @Override
+    protected List<String> getSchemaNames() {
+        Collection<String> schemaNames = ProxyContext.getInstance().getAllSchemaNames();
+        return schemaNames.stream().filter(AbstractDatabaseMetadataExecutor::hasDatasource).collect(Collectors.toList());
+    }
+    
+    @Override
+    protected void rowPostProcessing(final String schemaName, final Map<String, Object> rowMap, final Map<String, String> aliasMap) {
+        buildColumnNames(aliasMap);
+        ShardingSphereResource resource = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData(schemaName).getResource();
+        Set<String> catalogs = resource.getDataSources().keySet().stream().map(each -> resource.getDataSourcesMetaData().getDataSourceMetaData(each).getCatalog()).collect(Collectors.toSet());
+        databaseNameAlias = aliasMap.getOrDefault(DATABASE_NAME, "");
+        String rowValue = rowMap.getOrDefault(databaseNameAlias, "").toString();
+        if (catalogs.contains(rowValue)) {
+            rowMap.replace(databaseNameAlias, schemaName);
+        } else {
+            rowMap.clear();
+        }
+    }
+    
+    private void buildColumnNames(final Map<String, String> aliasMap) {
+        aliasMap.forEach((key, value) -> {
+            if (!value.isEmpty()) {
+                columnNames.add(value);
+            } else {
+                columnNames.add(key);
+            }
+        });
+        
+    }
+    
+    private Map<String, Object> getDefaultRowData(final String schemaName) {
+        Map<String, Object> result;
+        if (columnNames.isEmpty()) {
+            columnNames.addAll(getDefaultColumnNames());
+        }
+        result = columnNames.stream().collect(Collectors.toMap(each -> each, each -> ""));
+        result.replace(databaseNameAlias, schemaName);
+        return result;
+    }
+    
+    private Set<String> getDefaultColumnNames() {
+        Collection<ProjectionSegment> projections = sqlStatement.getProjections().getProjections();
+        if (projections.stream().anyMatch(each -> !(each instanceof ColumnProjectionSegment))) {
+            return Collections.singleton(databaseNameAlias);
+        } else {
+            return projections.stream().map(each -> {
+                ColumnProjectionSegment segment = (ColumnProjectionSegment) each;
+                return segment.getAlias().isPresent() ? segment.getAlias().get() : segment.getColumn().getIdentifier().getValue();
+            }).collect(Collectors.toCollection(LinkedHashSet::new));
+        }
+    }
+}
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutorFactory b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutorFactory
index 3913edc..92a43c6 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutorFactory
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutorFactory
@@ -16,3 +16,4 @@
 #
 
 org.apache.shardingsphere.proxy.backend.text.admin.mysql.MySQLAdminExecutorFactory
+org.apache.shardingsphere.proxy.backend.text.admin.postgresql.PostgreSQLAdminExecutorFactory
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationExecutorTest.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationExecutorTest.java
index 0bf17b4..07694d7 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationExecutorTest.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationExecutorTest.java
@@ -34,7 +34,7 @@ import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistService;
 import org.apache.shardingsphere.proxy.backend.communication.jdbc.connection.BackendConnection;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
-import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.information.AbstractSelectInformationExecutor.DefaultSelectInformationExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.AbstractDatabaseMetadataExecutor.DefaultDatabaseMetadataExecutor;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import org.junit.Before;
@@ -184,7 +184,7 @@ public final class SelectInformationExecutorTest {
         Map<String, ShardingSphereMetaData> metaDataMap = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaDataMap();
         metaDataMap.put("demo_ds_0", getMetaData());
         metaDataMap.put("test", mock(ShardingSphereMetaData.class));
-        DefaultSelectInformationExecutor selectExecutor = new DefaultSelectInformationExecutor(sql);
+        DefaultDatabaseMetadataExecutor selectExecutor = new DefaultDatabaseMetadataExecutor(sql);
         selectExecutor.execute(mock(BackendConnection.class));
         assertThat(selectExecutor.getRows().get(0).get("sn"), is("demo_ds_0"));
         assertThat(selectExecutor.getRows().get(0).get("DEFAULT_CHARACTER_SET_NAME"), is("utf8mb4"));
@@ -198,7 +198,7 @@ public final class SelectInformationExecutorTest {
         mockResultSet(mockMap, false);
         Map<String, ShardingSphereMetaData> metaDataMap = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaDataMap();
         metaDataMap.put("sharding_db", getMetaData());
-        DefaultSelectInformationExecutor defaultSelectMetaDataExecutor = new DefaultSelectInformationExecutor(sql);
+        DefaultDatabaseMetadataExecutor defaultSelectMetaDataExecutor = new DefaultDatabaseMetadataExecutor(sql);
         defaultSelectMetaDataExecutor.execute(mock(BackendConnection.class));
         assertThat(defaultSelectMetaDataExecutor.getQueryResultMetaData().getColumnCount(), is(mockMap.size()));
         while (defaultSelectMetaDataExecutor.getMergedResult().next()) {
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/PostgreSQLAdminExecutorFactoryTest.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/PostgreSQLAdminExecutorFactoryTest.java
new file mode 100644
index 0000000..9b7f5ec
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/PostgreSQLAdminExecutorFactoryTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.proxy.backend.text.admin.postgresql;
+
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.postgresql.executor.SelectDatabaseExecutor;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
+import org.junit.Test;
+
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public final class PostgreSQLAdminExecutorFactoryTest {
+    
+    private final PostgreSQLAdminExecutorFactory postgreSQLAdminExecutorFactory = new PostgreSQLAdminExecutorFactory();
+    
+    @Test
+    public void assertNewInstanceWithMySQLShowFunctionStatusStatement() {
+        SelectStatement statement = mock(SelectStatement.class);
+        SimpleTableSegment tableSegment = mock(SimpleTableSegment.class);
+        when(tableSegment.getTableName()).thenReturn(new TableNameSegment(0, 0, new IdentifierValue("pg_database")));
+        when(statement.getFrom()).thenReturn(tableSegment);
+        Optional<DatabaseAdminExecutor> executorOptional = postgreSQLAdminExecutorFactory.newInstance(statement, "");
+        assertTrue(executorOptional.isPresent());
+        assertThat(executorOptional.get(), instanceOf(SelectDatabaseExecutor.class));
+    }
+    
+}
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationExecutorTest.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectDatabaseExecutorTest.java
similarity index 70%
copy from shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationExecutorTest.java
copy to shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectDatabaseExecutorTest.java
index 0bf17b4..1a4d22b 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/information/SelectInformationExecutorTest.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectDatabaseExecutorTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.information;
+package org.apache.shardingsphere.proxy.backend.text.admin.postgresql.executor;
 
 import com.zaxxer.hikari.pool.HikariProxyResultSet;
 import org.apache.shardingsphere.infra.config.properties.ConfigurationProperties;
@@ -34,7 +34,6 @@ import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistService;
 import org.apache.shardingsphere.proxy.backend.communication.jdbc.connection.BackendConnection;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
-import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.information.AbstractSelectInformationExecutor.DefaultSelectInformationExecutor;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import org.junit.Before;
@@ -62,7 +61,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
-public final class SelectInformationExecutorTest {
+public final class SelectDatabaseExecutorTest {
     
     private static final ResultSet RESULT_SET = mock(HikariProxyResultSet.class);
     
@@ -113,25 +112,28 @@ public final class SelectInformationExecutorTest {
     
     @Test
     public void assertSelectSchemataExecute() throws SQLException {
-        final String sql = "SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA";
+        final String sql = "SELECT d.oid, d.datname AS databasename, d.datacl, d.datistemplate, d.datallowconn, pg_get_userbyid(d.datdba) AS databaseowner," 
+                + " d.datcollate, d.datctype, shobj_description(d.oid, 'pg_database') AS description, d.datconnlimit, t.spcname, d.encoding, pg_encoding_to_char(d.encoding) AS encodingname " 
+                + "FROM pg_database d LEFT JOIN pg_tablespace t ON d.dattablespace = t.oid;";
         final SQLStatement sqlStatement = new ShardingSphereSQLParserEngine("MySQL", new ConfigurationProperties(new Properties())).parse(sql, false);
         Map<String, String> mockResultSetMap = new HashMap<>();
-        mockResultSetMap.put("SCHEMA_NAME", "demo_ds_0");
-        mockResultSetMap.put("DEFAULT_CHARACTER_SET_NAME", "utf8mb4_0900_ai_ci");
-        mockResultSetMap.put("DEFAULT_COLLATION_NAME", "utf8mb4");
+        mockResultSetMap.put("databasename", "demo_ds_0");
+        mockResultSetMap.put("databaseowner", "postgres");
+        mockResultSetMap.put("datconnlimit", "-1");
+        mockResultSetMap.put("datctype", "en_US.utf8");
         mockResultSet(mockResultSetMap, true, false);
         Map<String, ShardingSphereMetaData> metaDataMap = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaDataMap();
         metaDataMap.put("sharding_db", getMetaData());
         metaDataMap.put("test", mock(ShardingSphereMetaData.class));
-        SelectInformationSchemataExecutor selectSchemataExecutor = new SelectInformationSchemataExecutor((SelectStatement) sqlStatement, sql);
+        SelectDatabaseExecutor selectSchemataExecutor = new SelectDatabaseExecutor((SelectStatement) sqlStatement, sql);
         selectSchemataExecutor.execute(mock(BackendConnection.class));
         assertThat(selectSchemataExecutor.getQueryResultMetaData().getColumnCount(), is(mockResultSetMap.size()));
         int count = 0;
         while (selectSchemataExecutor.getMergedResult().next()) {
             count++;
             if ("sharding_db".equals(selectSchemataExecutor.getMergedResult().getValue(1, String.class))) {
-                assertThat(selectSchemataExecutor.getMergedResult().getValue(2, String.class), is("utf8mb4"));
-                assertThat(selectSchemataExecutor.getMergedResult().getValue(3, String.class), is("utf8mb4_0900_ai_ci"));
+                assertThat(selectSchemataExecutor.getMergedResult().getValue(2, String.class), is("postgres"));
+                assertThat(selectSchemataExecutor.getMergedResult().getValue(3, String.class), is("-1"));
             } else if ("test".equals(selectSchemataExecutor.getMergedResult().getValue(1, String.class))) {
                 assertThat(selectSchemataExecutor.getMergedResult().getValue(2, String.class), is(""));
                 assertThat(selectSchemataExecutor.getMergedResult().getValue(3, String.class), is(""));
@@ -143,66 +145,54 @@ public final class SelectInformationExecutorTest {
     }
     
     @Test
-    public void assertSelectSchemataInSchemaWithoutDataSourceExecute() throws SQLException {
-        final String sql = "SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME, DEFAULT_ENCRYPTION FROM information_schema.SCHEMATA";
+    public void assertSelectSchemataWithoutDataSourceExecute1() throws SQLException {
+        final String sql = "SELECT d.oid, d.datname AS databasename, d.datacl, d.datistemplate, d.datallowconn, pg_get_userbyid(d.datdba) AS databaseowner, " 
+                + "d.datcollate, d.datctype, shobj_description(d.oid, 'pg_database') AS description, d.datconnlimit, t.spcname, d.encoding, pg_encoding_to_char(d.encoding) AS encodingname " 
+                + "FROM pg_database d LEFT JOIN pg_tablespace t ON d.dattablespace = t.oid;";
         final SQLStatement sqlStatement = new ShardingSphereSQLParserEngine("MySQL", new ConfigurationProperties(new Properties())).parse(sql, false);
         Map<String, String> mockResultSetMap = new HashMap<>();
-        mockResultSetMap.put("SCHEMA_NAME", "demo_ds_0");
-        mockResultSetMap.put("DEFAULT_CHARACTER_SET_NAME", "utf8mb4_0900_ai_ci");
-        mockResultSetMap.put("DEFAULT_COLLATION_NAME", "utf8mb4");
-        mockResultSetMap.put("DEFAULT_ENCRYPTION", "NO");
+        mockResultSetMap.put("databasename", "demo_ds_0");
+        mockResultSetMap.put("databaseowner", "postgres");
+        mockResultSetMap.put("datconnlimit", "-1");
+        mockResultSetMap.put("datctype", "en_US.utf8");
         mockResultSet(mockResultSetMap, false);
         Map<String, ShardingSphereMetaData> metaDataMap = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaDataMap();
         metaDataMap.put("sharding_db", mock(ShardingSphereMetaData.class));
-        SelectInformationSchemataExecutor selectSchemataExecutor = new SelectInformationSchemataExecutor((SelectStatement) sqlStatement, sql);
+        SelectDatabaseExecutor selectSchemataExecutor = new SelectDatabaseExecutor((SelectStatement) sqlStatement, sql);
         selectSchemataExecutor.execute(mock(BackendConnection.class));
-        assertThat(selectSchemataExecutor.getQueryResultMetaData().getColumnCount(), is(mockResultSetMap.size()));
         while (selectSchemataExecutor.getMergedResult().next()) {
             assertThat(selectSchemataExecutor.getMergedResult().getValue(1, String.class), is("sharding_db"));
-            assertThat(selectSchemataExecutor.getMergedResult().getValue(2, String.class), is(""));
-            assertThat(selectSchemataExecutor.getMergedResult().getValue(3, String.class), is(""));
-            assertThat(selectSchemataExecutor.getMergedResult().getValue(4, String.class), is(""));
         }
     }
     
     @Test
-    public void assertSelectSchemataInNoSchemaExecute() throws SQLException {
-        final String sql = "SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME, DEFAULT_ENCRYPTION FROM information_schema.SCHEMATA";
+    public void assertSelectSchemataWithoutDataSourceExecuteAndWithColumnProjectionSegment() throws SQLException {
+        final String sql = "SELECT d.oid, d.datname AS databasename, d.datacl, d.datistemplate FROM pg_database d LEFT JOIN pg_tablespace t ON d.dattablespace = t.oid;";
         final SQLStatement sqlStatement = new ShardingSphereSQLParserEngine("MySQL", new ConfigurationProperties(new Properties())).parse(sql, false);
-        SelectInformationSchemataExecutor selectSchemataExecutor = new SelectInformationSchemataExecutor((SelectStatement) sqlStatement, sql);
-        selectSchemataExecutor.execute(mock(BackendConnection.class));
-        assertThat(selectSchemataExecutor.getQueryResultMetaData().getColumnCount(), is(0));
-    }
-
-    @Test
-    public void assertSelectSchemaAliasExecute() throws SQLException {
-        final String sql = "SELECT SCHEMA_NAME AS sn, DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA";
         Map<String, String> mockResultSetMap = new HashMap<>();
-        mockResultSetMap.put("sn", "demo_ds_0");
-        mockResultSetMap.put("DEFAULT_CHARACTER_SET_NAME", "utf8mb4");
+        mockResultSetMap.put("databasename", "demo_ds_0");
+        mockResultSetMap.put("databaseowner", "postgres");
+        mockResultSetMap.put("datconnlimit", "-1");
+        mockResultSetMap.put("datctype", "en_US.utf8");
         mockResultSet(mockResultSetMap, false);
         Map<String, ShardingSphereMetaData> metaDataMap = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaDataMap();
-        metaDataMap.put("demo_ds_0", getMetaData());
-        metaDataMap.put("test", mock(ShardingSphereMetaData.class));
-        DefaultSelectInformationExecutor selectExecutor = new DefaultSelectInformationExecutor(sql);
-        selectExecutor.execute(mock(BackendConnection.class));
-        assertThat(selectExecutor.getRows().get(0).get("sn"), is("demo_ds_0"));
-        assertThat(selectExecutor.getRows().get(0).get("DEFAULT_CHARACTER_SET_NAME"), is("utf8mb4"));
+        metaDataMap.put("sharding_db", mock(ShardingSphereMetaData.class));
+        SelectDatabaseExecutor selectSchemataExecutor = new SelectDatabaseExecutor((SelectStatement) sqlStatement, sql);
+        selectSchemataExecutor.execute(mock(BackendConnection.class));
+        while (selectSchemataExecutor.getMergedResult().next()) {
+            assertThat(selectSchemataExecutor.getMergedResult().getValue(1, String.class), is(""));
+            assertThat(selectSchemataExecutor.getMergedResult().getValue(2, String.class), is("sharding_db"));
+            assertThat(selectSchemataExecutor.getMergedResult().getValue(3, String.class), is(""));
+            assertThat(selectSchemataExecutor.getMergedResult().getValue(4, String.class), is(""));
+        }
     }
     
     @Test
-    public void assertDefaultExecute() throws SQLException {
-        final String sql = "SELECT COUNT(*) AS support_ndb FROM information_schema.ENGINES WHERE Engine = 'ndbcluster'";
-        Map<String, String> mockMap = new HashMap<>();
-        mockMap.put("support_ndb", "0");
-        mockResultSet(mockMap, false);
-        Map<String, ShardingSphereMetaData> metaDataMap = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaDataMap();
-        metaDataMap.put("sharding_db", getMetaData());
-        DefaultSelectInformationExecutor defaultSelectMetaDataExecutor = new DefaultSelectInformationExecutor(sql);
-        defaultSelectMetaDataExecutor.execute(mock(BackendConnection.class));
-        assertThat(defaultSelectMetaDataExecutor.getQueryResultMetaData().getColumnCount(), is(mockMap.size()));
-        while (defaultSelectMetaDataExecutor.getMergedResult().next()) {
-            assertThat(defaultSelectMetaDataExecutor.getMergedResult().getValue(1, String.class), is("0"));
-        }
+    public void assertSelectSchemataInNoSchemaExecute() throws SQLException {
+        final String sql = "SELECT d.oid, d.datname AS databasename, d.datacl, d.datistemplate FROM pg_database d LEFT JOIN pg_tablespace t ON d.dattablespace = t.oid;";
+        final SQLStatement sqlStatement = new ShardingSphereSQLParserEngine("MySQL", new ConfigurationProperties(new Properties())).parse(sql, false);
+        SelectDatabaseExecutor selectSchemataExecutor = new SelectDatabaseExecutor((SelectStatement) sqlStatement, sql);
+        selectSchemataExecutor.execute(mock(BackendConnection.class));
+        assertThat(selectSchemataExecutor.getQueryResultMetaData().getColumnCount(), is(0));
     }
 }