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 7be8219 Supports querying pg_tablespace, pg_namespace (#13548)
7be8219 is described below
commit 7be8219db8bf9c73110a41ba5506a252ef667579
Author: lanchengx <[email protected]>
AuthorDate: Thu Nov 11 05:33:44 2021 -0600
Supports querying pg_tablespace, pg_namespace (#13548)
* Client supports querying pg_tablespace,pg_namespace
* Client supports querying pg_tablespace,pg_namespace
* Client supports querying pg_tablespace,pg_namespace
* Client supports querying pg_tablespace,pg_namespace
---
.../executor/AbstractDatabaseMetadataExecutor.java | 35 ++++--
.../postgresql/PostgreSQLAdminExecutorFactory.java | 12 ++
.../executor/SelectDatabaseExecutor.java | 6 +-
.../postgresql/executor/SelectTableExecutor.java | 81 ++++++++++++
.../executor/SelectTableExecutorTest.java | 137 +++++++++++++++++++++
.../src/main/antlr4/imports/postgresql/BaseRule.g4 | 1 +
6 files changed, 256 insertions(+), 16 deletions(-)
diff --git
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
index 34b7ad3..312b26b 100644
---
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
+++
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
@@ -40,7 +40,8 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collections;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -66,17 +67,18 @@ public abstract class AbstractDatabaseMetadataExecutor
implements DatabaseAdminQ
public final void execute(final BackendConnection backendConnection)
throws SQLException {
List<String> schemaNames = getSchemaNames();
for (String schemaName : schemaNames) {
+ initSchemaData(schemaName);
getSourceData(schemaName, resultSet -> handleResultSet(schemaName,
resultSet));
}
- addDefaultRow(rows);
+ createPreProcessing();
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<>();
+ Map<String, Object> rowMap = new LinkedHashMap<>();
+ Map<String, String> aliasMap = new LinkedHashMap<>();
ResultSetMetaData metaData = resultSet.getMetaData();
for (int i = 1; i < metaData.getColumnCount() + 1; i++) {
aliasMap.put(metaData.getColumnName(i),
metaData.getColumnLabel(i));
@@ -90,6 +92,11 @@ public abstract class AbstractDatabaseMetadataExecutor
implements DatabaseAdminQ
}
/**
+ * Initialize the schema data.
+ */
+ protected abstract void initSchemaData(String schemaName);
+
+ /**
* Get the schema names as a condition for SQL execution.
*
* @return schema names
@@ -99,9 +106,8 @@ public abstract class AbstractDatabaseMetadataExecutor
implements DatabaseAdminQ
/**
* Add default row data.
*
- * @param rows row
*/
- protected abstract void addDefaultRow(LinkedList<Map<String, Object>>
rows);
+ protected abstract void createPreProcessing();
/**
* Get the source object of the row data.
@@ -123,13 +129,13 @@ public abstract class AbstractDatabaseMetadataExecutor
implements DatabaseAdminQ
private MergedResult createMergedResult() {
List<MemoryQueryResultDataRow> resultDataRows = rows.stream()
- .map(each -> new MemoryQueryResultDataRow(new
LinkedList<>(each.values()))).collect(Collectors.toList());
+ .map(each -> new MemoryQueryResultDataRow(new
LinkedList<>(each.values()))).collect(Collectors.toCollection(LinkedList::new));
return new TransparentMergedResult(new
RawMemoryQueryResult(queryResultMetaData, resultDataRows));
}
private RawQueryResultMetaData createQueryResultMetaData() {
- List<RawQueryResultColumnMetaData> columns =
rows.stream().flatMap(each ->
each.keySet().stream()).collect(Collectors.toSet())
- .stream().map(each -> new RawQueryResultColumnMetaData("",
each, each, Types.VARCHAR, "VARCHAR", 20, 0)).collect(Collectors.toList());
+ List<RawQueryResultColumnMetaData> columns =
rows.stream().flatMap(each ->
each.keySet().stream()).collect(Collectors.toCollection(LinkedHashSet::new))
+ .stream().map(each -> new RawQueryResultColumnMetaData("",
each, each, Types.VARCHAR, "VARCHAR", 20,
0)).collect(Collectors.toCollection(LinkedList::new));
return new RawQueryResultMetaData(columns);
}
@@ -155,7 +161,11 @@ public abstract class AbstractDatabaseMetadataExecutor
implements DatabaseAdminQ
public DefaultDatabaseMetadataExecutor(final String sql) {
this.sql = sql;
}
-
+
+ @Override
+ protected void initSchemaData(final String schemaName) {
+ }
+
/**
* Get the schema names as a condition for SQL execution.
*
@@ -194,14 +204,13 @@ public abstract class AbstractDatabaseMetadataExecutor
implements DatabaseAdminQ
@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) {
+ protected void createPreProcessing() {
}
}
}
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
index c6b6c96..7ad3603 100644
---
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
@@ -17,9 +17,11 @@
package org.apache.shardingsphere.proxy.backend.text.admin.postgresql;
+import
org.apache.shardingsphere.proxy.backend.text.admin.executor.AbstractDatabaseMetadataExecutor.DefaultDatabaseMetadataExecutor;
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.proxy.backend.text.admin.postgresql.executor.SelectTableExecutor;
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;
@@ -35,8 +37,12 @@ import java.util.stream.Collectors;
*/
public final class PostgreSQLAdminExecutorFactory implements
DatabaseAdminExecutorFactory {
+ private static final String PG_TABLESPACE = "pg_tablespace";
+
private static final String PG_DATABASE = "pg_database";
+ private static final String PG_NAMESPACE = "pg_namespace";
+
@Override
public Optional<DatabaseAdminExecutor> newInstance(final SQLStatement
sqlStatement) {
return Optional.empty();
@@ -49,6 +55,12 @@ public final class PostgreSQLAdminExecutorFactory implements
DatabaseAdminExecut
if (selectedTableNames.contains(PG_DATABASE)) {
return Optional.of(new
SelectDatabaseExecutor((SelectStatement) sqlStatement, sql));
}
+ if (selectedTableNames.contains(PG_TABLESPACE)) {
+ return Optional.of(new SelectTableExecutor(sql));
+ }
+ if (selectedTableNames.contains(PG_NAMESPACE)) {
+ return Optional.of(new DefaultDatabaseMetadataExecutor(sql));
+ }
}
return Optional.empty();
}
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
index 9e1d923..eaea1ee 100644
---
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
@@ -35,7 +35,7 @@ import java.util.Set;
import java.util.stream.Collectors;
/**
- * Schemata query executor, used to query the schemata table.
+ * Database metadata query executor, used to query the schemata database.
*/
public final class SelectDatabaseExecutor extends
DefaultDatabaseMetadataExecutor {
@@ -53,10 +53,10 @@ public final class SelectDatabaseExecutor extends
DefaultDatabaseMetadataExecuto
}
@Override
- protected void addDefaultRow(final LinkedList<Map<String, Object>> rows) {
+ protected void createPreProcessing() {
LinkedList<String> schemaWithoutDataSource =
ProxyContext.getInstance().getAllSchemaNames().stream()
.filter(each ->
!hasDatasource(each)).collect(Collectors.toCollection(LinkedList::new));
- schemaWithoutDataSource.forEach(each ->
rows.addLast(getDefaultRowData(each)));
+ schemaWithoutDataSource.forEach(each ->
getRows().addLast(getDefaultRowData(each)));
}
@Override
diff --git
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectTableExecutor.java
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectTableExecutor.java
new file mode 100644
index 0000000..366774d
--- /dev/null
+++
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectTableExecutor.java
@@ -0,0 +1,81 @@
+/*
+ * 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.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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Database metadata query executor, used to query table.
+ */
+public final class SelectTableExecutor extends DefaultDatabaseMetadataExecutor
{
+
+ private static final String REL_NAME = "relname";
+
+ private static final String TABLE_NAME = "tablename";
+
+ private String actualTableName = "";
+
+ private List<String> tableNames;
+
+ public SelectTableExecutor(final String sql) {
+ super(sql);
+ }
+
+ @Override
+ protected void initSchemaData(final String schemaName) {
+ tableNames = new
ArrayList<>(ProxyContext.getInstance().getMetaData(schemaName).getSchema().getAllTableNames());
+ }
+
+ @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) {
+ if (actualTableName.isEmpty()) {
+ actualTableName = aliasMap.getOrDefault(REL_NAME,
aliasMap.getOrDefault(TABLE_NAME, ""));
+ }
+ }
+
+ @Override
+ protected void createPreProcessing() {
+ if (actualTableName.isEmpty()) {
+ return;
+ }
+ if (tableNames.size() > getRows().size()) {
+ return;
+ }
+ List<Map<String, Object>> subList = new
LinkedList<>(getRows().subList(0, tableNames.size()));
+ for (int i = 0; i < subList.size(); i++) {
+ subList.get(i).replace(actualTableName, tableNames.get(i));
+ }
+ getRows().clear();
+ getRows().addAll(subList);
+ }
+}
diff --git
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectTableExecutorTest.java
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectTableExecutorTest.java
new file mode 100644
index 0000000..3369ef6
--- /dev/null
+++
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/postgresql/executor/SelectTableExecutorTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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 com.zaxxer.hikari.pool.HikariProxyResultSet;
+import
org.apache.shardingsphere.infra.config.properties.ConfigurationProperties;
+import org.apache.shardingsphere.infra.database.type.dialect.MySQLDatabaseType;
+import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import
org.apache.shardingsphere.infra.metadata.resource.CachedDatabaseMetaData;
+import org.apache.shardingsphere.infra.metadata.resource.DataSourcesMetaData;
+import
org.apache.shardingsphere.infra.metadata.resource.ShardingSphereResource;
+import
org.apache.shardingsphere.infra.metadata.rule.ShardingSphereRuleMetaData;
+import org.apache.shardingsphere.infra.metadata.schema.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.metadata.schema.model.TableMetaData;
+import org.apache.shardingsphere.infra.optimize.context.OptimizerContext;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+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.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import javax.sql.DataSource;
+import java.lang.reflect.Field;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class SelectTableExecutorTest {
+
+ private static final ResultSet RESULT_SET =
mock(HikariProxyResultSet.class);
+
+ @Before
+ public void setUp() throws IllegalAccessException, NoSuchFieldException,
SQLException {
+ Field contextManagerField =
ProxyContext.getInstance().getClass().getDeclaredField("contextManager");
+ contextManagerField.setAccessible(true);
+ ContextManager contextManager = mock(ContextManager.class,
RETURNS_DEEP_STUBS);
+ MetaDataContexts metaDataContexts = new
MetaDataContexts(mock(MetaDataPersistService.class), new HashMap<>(),
mock(ShardingSphereRuleMetaData.class),
+ mock(ExecutorEngine.class), new ConfigurationProperties(new
Properties()), mock(OptimizerContext.class));
+
when(contextManager.getMetaDataContexts()).thenReturn(metaDataContexts);
+ ProxyContext.getInstance().init(contextManager);
+ }
+
+ private void mockResultSet(final Map<String, String> mockMap, final
Boolean... values) throws SQLException {
+ ResultSetMetaData metaData = mock(ResultSetMetaData.class);
+ List<String> keys = new ArrayList<>(mockMap.keySet());
+ for (int i = 0; i < keys.size(); i++) {
+ when(metaData.getColumnName(i + 1)).thenReturn(keys.get(i));
+ when(metaData.getColumnLabel(i + 1)).thenReturn(keys.get(i));
+ when(RESULT_SET.getString(i +
1)).thenReturn(mockMap.get(keys.get(i)));
+ }
+ when(RESULT_SET.next()).thenReturn(true, false);
+ when(metaData.getColumnCount()).thenReturn(mockMap.size());
+ when(RESULT_SET.getMetaData()).thenReturn(metaData);
+ }
+
+ private ShardingSphereMetaData getMetaData() throws SQLException {
+ return new ShardingSphereMetaData("sharding_db",
+ new ShardingSphereResource(mockDatasourceMap(),
mockDataSourcesMetaData(), mock(CachedDatabaseMetaData.class),
mock(MySQLDatabaseType.class)),
+ mock(ShardingSphereRuleMetaData.class), new
ShardingSphereSchema(Collections.singletonMap("t_order",
mock(TableMetaData.class))));
+ }
+
+ private Map<String, DataSource> mockDatasourceMap() throws SQLException {
+ DataSource dataSource = mock(DataSource.class, RETURNS_DEEP_STUBS);
+
when(dataSource.getConnection().prepareStatement(any(String.class)).executeQuery()).thenReturn(RESULT_SET);
+ Map<String, DataSource> dataSourceMap = new HashMap<>();
+ dataSourceMap.put("ds_0", dataSource);
+ return dataSourceMap;
+ }
+
+ private DataSourcesMetaData mockDataSourcesMetaData() {
+ DataSourcesMetaData meta = mock(DataSourcesMetaData.class,
RETURNS_DEEP_STUBS);
+
when(meta.getDataSourceMetaData("ds_0").getCatalog()).thenReturn("demo_ds_0");
+ return meta;
+ }
+
+ @Test
+ public void assertSelectSchemataExecute() throws SQLException {
+ final String sql = "SELECT c.oid, n.nspname AS schemaname, c.relname
AS tablename from pg_tablespace";
+ Map<String, String> mockResultSetMap = new LinkedHashMap<>();
+ mockResultSetMap.put("tablename", "t_order_1");
+ mockResultSetMap.put("c.oid", "0000");
+ mockResultSetMap.put("schemaname", "public");
+ mockResultSet(mockResultSetMap, true, false);
+ Map<String, ShardingSphereMetaData> metaDataMap =
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaDataMap();
+ metaDataMap.put("sharding_db", getMetaData());
+ SelectTableExecutor selectSchemataExecutor = new
SelectTableExecutor(sql);
+ selectSchemataExecutor.execute(mock(BackendConnection.class));
+
assertThat(selectSchemataExecutor.getQueryResultMetaData().getColumnCount(),
is(mockResultSetMap.size()));
+ int count = 0;
+ while (selectSchemataExecutor.getMergedResult().next()) {
+ count++;
+ if
("t_order".equals(selectSchemataExecutor.getMergedResult().getValue(1,
String.class))) {
+
assertThat(selectSchemataExecutor.getMergedResult().getValue(2, String.class),
is("0000"));
+
assertThat(selectSchemataExecutor.getMergedResult().getValue(3, String.class),
is("public"));
+ } else {
+ fail("expected : `t_order`");
+ }
+ }
+ assertThat(count, is(1));
+ }
+}
diff --git
a/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/antlr4/imports/postgresql/BaseRule.g4
b/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/antlr4/imports/postgresql/BaseRule.g4
index 94268c9..99651b1 100644
---
a/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/antlr4/imports/postgresql/BaseRule.g4
+++
b/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/antlr4/imports/postgresql/BaseRule.g4
@@ -420,6 +420,7 @@ unreservedWord
| YES
| ZONE
| JSON
+ | PARAM
;
typeFuncNameKeyword