This is an automated email from the ASF dual-hosted git repository.
terrymanu 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 ebf00fc95d0 Fix Hive and Presto metadata loading (#39835)
ebf00fc95d0 is described below
commit ebf00fc95d0e2cc6dee810a31196a9b626856a9c
Author: Liang Zhang <[email protected]>
AuthorDate: Sun Sep 13 22:14:49 2026 +0800
Fix Hive and Presto metadata loading (#39835)
* Enforce code handoff review output
* Fix Hive and Presto metadata loading
---
.../data/loader/type/ColumnMetaDataLoader.java | 3 +-
.../metadata/data/loader/HiveMetaDataLoader.java | 46 ++++++++++--
.../data/loader/HiveMetaDataLoaderTest.java | 76 +++++++++++++-------
.../metadata/data/loader/PrestoMetaDataLoader.java | 50 +++++++++++--
.../data/loader/PrestoMetaDataLoaderTest.java | 82 ++++++++++++++--------
5 files changed, 191 insertions(+), 66 deletions(-)
diff --git
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/ColumnMetaDataLoader.java
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/ColumnMetaDataLoader.java
index b54b004482e..7f97a2d8464 100644
---
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/ColumnMetaDataLoader.java
+++
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/ColumnMetaDataLoader.java
@@ -74,7 +74,8 @@ public final class ColumnMetaDataLoader {
String tableName = resultSet.getString(TABLE_NAME);
if (Objects.equals(tableNamePattern, tableName)) {
String columnName = resultSet.getString(COLUMN_NAME);
- columnTypes.add(resultSet.getInt(DATA_TYPE));
+ int columnType = resultSet.getInt(DATA_TYPE);
+ columnTypes.add(columnType);
primaryKeyFlags.add(primaryKeys.contains(columnName));
nullableFlags.add("YES".equals(resultSet.getString(IS_NULLABLE)));
columnNames.add(columnName);
diff --git
a/database/connector/dialect/hive/src/main/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoader.java
b/database/connector/dialect/hive/src/main/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoader.java
index faccb2ef238..68798ea87ab 100644
---
a/database/connector/dialect/hive/src/main/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoader.java
+++
b/database/connector/dialect/hive/src/main/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoader.java
@@ -24,6 +24,7 @@ import
org.apache.shardingsphere.database.connector.core.metadata.data.model.Col
import
org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
import
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import
org.apache.shardingsphere.database.connector.core.metadata.database.datatype.DataTypeRegistry;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.enums.TableType;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -35,6 +36,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
@@ -47,14 +49,20 @@ import java.util.stream.Collectors;
*/
public final class HiveMetaDataLoader implements DialectMetaDataLoader {
+ private static final String VIEW_META_DATA_SQL = "SELECT TABLE_NAME FROM
INFORMATION_SCHEMA.TABLES"
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND TABLE_TYPE='VIEW'
AND UPPER(TABLE_NAME) IN (%s)";
+
@Override
public Collection<SchemaMetaData> load(final MetaDataLoaderMaterial
material) throws SQLException {
Collection<TableMetaData> tableMetaData = new LinkedList<>();
if (loadInformationSchemaFlag(material)) {
try (Connection connection =
material.getDataSource().getConnection()) {
- Map<String, Collection<ColumnMetaData>> columnMetaDataMap =
loadColumnMetaDataMap(connection, material.getActualTableNames());
+ String schemaName = connection.getSchema();
+ Map<String, Collection<ColumnMetaData>> columnMetaDataMap =
loadColumnMetaDataMap(connection, schemaName, material.getActualTableNames());
+ Collection<String> viewNames = columnMetaDataMap.isEmpty() ?
Collections.emptySet() : loadViewNames(connection, schemaName,
columnMetaDataMap.keySet());
for (Entry<String, Collection<ColumnMetaData>> entry :
columnMetaDataMap.entrySet()) {
- tableMetaData.add(new TableMetaData(entry.getKey(),
entry.getValue(), Collections.emptyList(), Collections.emptyList()));
+ tableMetaData.add(new TableMetaData(
+ entry.getKey(), entry.getValue(),
Collections.emptyList(), Collections.emptyList(),
viewNames.contains(entry.getKey()) ? TableType.VIEW : TableType.TABLE));
}
}
return Collections.singleton(new
SchemaMetaData(material.getDefaultSchemaName(), tableMetaData));
@@ -76,10 +84,11 @@ public final class HiveMetaDataLoader implements
DialectMetaDataLoader {
}
@SuppressWarnings("CollectionWithoutInitialCapacity")
- private Map<String, Collection<ColumnMetaData>>
loadColumnMetaDataMap(final Connection connection, final Collection<String>
tables) throws SQLException {
+ private Map<String, Collection<ColumnMetaData>>
loadColumnMetaDataMap(final Connection connection, final String schemaName,
final Collection<String> tables) throws SQLException {
Map<String, Collection<ColumnMetaData>> result = new HashMap<>();
try (PreparedStatement preparedStatement =
connection.prepareStatement(getTableMetaDataSQL(tables))) {
preparedStatement.setString(1, "default");
+ preparedStatement.setString(2, schemaName);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
String tableName = resultSet.getString("TABLE_NAME");
@@ -96,18 +105,43 @@ public final class HiveMetaDataLoader implements
DialectMetaDataLoader {
private String getTableMetaDataSQL(final Collection<String> tables) {
if (tables.isEmpty()) {
- return "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG=? ORDER BY
ORDINAL_POSITION";
+ return "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS"
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? ORDER BY
ORDINAL_POSITION";
}
String tableNames = tables.stream().map(each -> String.format("'%s'",
each).toUpperCase()).collect(Collectors.joining(","));
return String.format("SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS"
- + " WHERE TABLE_CATALOG=? AND UPPER(TABLE_NAME) IN (%s) ORDER
BY ORDINAL_POSITION", tableNames);
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND
UPPER(TABLE_NAME) IN (%s) ORDER BY ORDINAL_POSITION", tableNames);
}
private ColumnMetaData loadColumnMetaData(final ResultSet resultSet)
throws SQLException {
String columnName = resultSet.getString("COLUMN_NAME");
String dataType = resultSet.getString("DATA_TYPE");
boolean isNullable = "YES".equals(resultSet.getString("IS_NULLABLE"));
- return new ColumnMetaData(columnName,
DataTypeRegistry.getDataType(getDatabaseType(), dataType).orElse(Types.OTHER),
Boolean.FALSE, Boolean.FALSE, false, Boolean.TRUE, false, isNullable);
+ return new ColumnMetaData(columnName,
DataTypeRegistry.getDataType(getDatabaseType(), dataType).orElse(Types.OTHER),
Boolean.FALSE, Boolean.FALSE,
+ isStringDataType(dataType), Boolean.TRUE, false, isNullable);
+ }
+
+ private boolean isStringDataType(final String dataType) {
+ String normalizedDataType = dataType.toLowerCase(Locale.ENGLISH);
+ return "string".equals(normalizedDataType) ||
normalizedDataType.startsWith("varchar") ||
normalizedDataType.startsWith("char");
+ }
+
+ private Collection<String> loadViewNames(final Connection connection,
final String schemaName, final Collection<String> tableNames) throws
SQLException {
+ Collection<String> result = new LinkedList<>();
+ try (PreparedStatement preparedStatement =
connection.prepareStatement(getViewMetaDataSQL(tableNames))) {
+ preparedStatement.setString(1, "default");
+ preparedStatement.setString(2, schemaName);
+ try (ResultSet resultSet = preparedStatement.executeQuery()) {
+ while (resultSet.next()) {
+ result.add(resultSet.getString("TABLE_NAME"));
+ }
+ }
+ }
+ return result;
+ }
+
+ private String getViewMetaDataSQL(final Collection<String> tableNames) {
+ return String.format(VIEW_META_DATA_SQL, tableNames.stream().map(each
-> String.format("'%s'",
each).toUpperCase(Locale.ENGLISH)).collect(Collectors.joining(",")));
}
@Override
diff --git
a/database/connector/dialect/hive/src/test/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoaderTest.java
b/database/connector/dialect/hive/src/test/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoaderTest.java
index cdf349d8508..fbcd3e2a779 100644
---
a/database/connector/dialect/hive/src/test/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoaderTest.java
+++
b/database/connector/dialect/hive/src/test/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoaderTest.java
@@ -26,6 +26,7 @@ import
org.apache.shardingsphere.database.connector.core.metadata.data.model.Col
import
org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
import
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import
org.apache.shardingsphere.database.connector.core.metadata.database.datatype.DataTypeRegistry;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.enums.TableType;
import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
@@ -56,6 +57,7 @@ import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(AutoMockExtension.class)
@@ -90,26 +92,39 @@ class HiveMetaDataLoaderTest {
@Test
void assertLoadWithInformationSchemaAndFilter() throws SQLException {
- DataSource dataSource =
mockDataSource(mockInformationSchemaConnection(true),
mockColumnMetaDataConnectionWithInformationSchemaAndFilter());
- Collection<SchemaMetaData> filteredSchemas = loader.load(new
MetaDataLoaderMaterial(Collections.singleton("target_table"), "ds_0",
dataSource, databaseType, "def_schema"));
- SchemaMetaData filteredSchema = filteredSchemas.iterator().next();
- TableMetaData filteredTable =
filteredSchema.getTables().iterator().next();
- Iterator<ColumnMetaData> filteredColumns =
filteredTable.getColumns().iterator();
- ColumnMetaData firstColumn = filteredColumns.next();
- assertThat(firstColumn.getName(), is("c1"));
- assertThat(firstColumn.getDataType(), is(Types.VARCHAR));
- assertTrue(firstColumn.isNullable());
- ColumnMetaData secondColumn = filteredColumns.next();
- assertThat(secondColumn.getDataType(), is(Types.OTHER));
- assertFalse(secondColumn.isNullable());
+ PreparedStatement columnMetaDataStatement =
mock(PreparedStatement.class);
+ PreparedStatement viewMetaDataStatement =
mock(PreparedStatement.class);
+ DataSource dataSource =
mockDataSource(mockInformationSchemaConnection(true),
+
mockColumnMetaDataConnectionWithInformationSchemaAndFilter(columnMetaDataStatement,
viewMetaDataStatement));
+ Collection<SchemaMetaData> actualSchemas = loader.load(new
MetaDataLoaderMaterial(Collections.singleton("target_table"), "ds_0",
dataSource, databaseType, "def_schema"));
+ SchemaMetaData actualSchema = actualSchemas.iterator().next();
+ TableMetaData actualTable = actualSchema.getTables().iterator().next();
+ assertThat(actualTable.getType(), is(TableType.VIEW));
+ Iterator<ColumnMetaData> actualColumns =
actualTable.getColumns().iterator();
+ ColumnMetaData actualFirstColumn = actualColumns.next();
+ assertThat(actualFirstColumn.getName(), is("c1"));
+ assertThat(actualFirstColumn.getDataType(), is(Types.VARCHAR));
+ assertTrue(actualFirstColumn.isCaseSensitive());
+ assertTrue(actualFirstColumn.isNullable());
+ ColumnMetaData actualSecondColumn = actualColumns.next();
+ assertThat(actualSecondColumn.getDataType(), is(Types.OTHER));
+ assertFalse(actualSecondColumn.isCaseSensitive());
+ assertFalse(actualSecondColumn.isNullable());
+ verify(columnMetaDataStatement).setString(1, "default");
+ verify(columnMetaDataStatement).setString(2, "foo_schema");
+ verify(viewMetaDataStatement).setString(1, "default");
+ verify(viewMetaDataStatement).setString(2, "foo_schema");
}
@Test
void assertLoadWithInformationSchemaWithoutFilter() throws SQLException {
DataSource dataSource =
mockDataSource(mockInformationSchemaConnection(true),
mockColumnMetaDataConnectionWithInformationSchemaWithoutFilter());
- Collection<SchemaMetaData> fullSchemas = loader.load(new
MetaDataLoaderMaterial(Collections.emptyList(), "ds_1", dataSource,
databaseType, "default_db"));
- SchemaMetaData fullSchema = fullSchemas.iterator().next();
- assertThat(fullSchema.getTables().iterator().next().getName(),
is("full_table"));
+ Collection<SchemaMetaData> actualSchemas = loader.load(new
MetaDataLoaderMaterial(Collections.emptyList(), "ds_1", dataSource,
databaseType, "default_db"));
+ SchemaMetaData actualSchema = actualSchemas.iterator().next();
+ TableMetaData actualTable = actualSchema.getTables().iterator().next();
+ assertThat(actualTable.getName(), is("full_table"));
+ assertThat(actualTable.getType(), is(TableType.TABLE));
+
assertFalse(actualTable.getColumns().iterator().next().isCaseSensitive());
}
@Test
@@ -140,19 +155,25 @@ class HiveMetaDataLoaderTest {
return result;
}
- private Connection
mockColumnMetaDataConnectionWithInformationSchemaAndFilter() throws
SQLException {
+ private Connection
mockColumnMetaDataConnectionWithInformationSchemaAndFilter(final
PreparedStatement columnMetaDataStatement, final PreparedStatement
viewMetaDataStatement) throws SQLException {
ResultSet resultSet = mock(ResultSet.class);
when(resultSet.next()).thenReturn(true, true, false);
when(resultSet.getString("TABLE_NAME")).thenReturn("target_table",
"target_table");
when(resultSet.getString("COLUMN_NAME")).thenReturn("c1", "c2");
when(resultSet.getString("DATA_TYPE")).thenReturn("string", "unknown");
when(resultSet.getString("IS_NULLABLE")).thenReturn("YES", "NO");
- PreparedStatement preparedStatement = mock(PreparedStatement.class);
- when(preparedStatement.executeQuery()).thenReturn(resultSet);
+ when(columnMetaDataStatement.executeQuery()).thenReturn(resultSet);
+ ResultSet viewResultSet = mock(ResultSet.class);
+ when(viewResultSet.next()).thenReturn(true, false);
+ when(viewResultSet.getString("TABLE_NAME")).thenReturn("target_table");
+ when(viewMetaDataStatement.executeQuery()).thenReturn(viewResultSet);
Connection connection = mock(Connection.class);
String sql = "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS "
- + "WHERE TABLE_CATALOG=? AND UPPER(TABLE_NAME) IN
('TARGET_TABLE') ORDER BY ORDINAL_POSITION";
- when(connection.prepareStatement(sql)).thenReturn(preparedStatement);
+ + "WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND
UPPER(TABLE_NAME) IN ('TARGET_TABLE') ORDER BY ORDINAL_POSITION";
+
when(connection.prepareStatement(sql)).thenReturn(columnMetaDataStatement);
+ String viewSql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND TABLE_TYPE='VIEW' AND
UPPER(TABLE_NAME) IN ('TARGET_TABLE')";
+
when(connection.prepareStatement(viewSql)).thenReturn(viewMetaDataStatement);
+ when(connection.getSchema()).thenReturn("foo_schema");
return connection;
}
@@ -163,11 +184,18 @@ class HiveMetaDataLoaderTest {
when(resultSet.getString("COLUMN_NAME")).thenReturn("id");
when(resultSet.getString("DATA_TYPE")).thenReturn("int");
when(resultSet.getString("IS_NULLABLE")).thenReturn("NO");
- PreparedStatement preparedStatement = mock(PreparedStatement.class);
- when(preparedStatement.executeQuery()).thenReturn(resultSet);
+ PreparedStatement columnMetaDataStatement =
mock(PreparedStatement.class);
+ when(columnMetaDataStatement.executeQuery()).thenReturn(resultSet);
+ PreparedStatement viewMetaDataStatement =
mock(PreparedStatement.class);
+ ResultSet viewResultSet = mock(ResultSet.class);
+ when(viewMetaDataStatement.executeQuery()).thenReturn(viewResultSet);
Connection result = mock(Connection.class);
- String sql = "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG=? ORDER BY
ORDINAL_POSITION";
- when(result.prepareStatement(sql)).thenReturn(preparedStatement);
+ String sql = "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS"
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? ORDER BY
ORDINAL_POSITION";
+ when(result.prepareStatement(sql)).thenReturn(columnMetaDataStatement);
+ String viewSql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND TABLE_TYPE='VIEW' AND
UPPER(TABLE_NAME) IN ('FULL_TABLE')";
+
when(result.prepareStatement(viewSql)).thenReturn(viewMetaDataStatement);
+ when(result.getSchema()).thenReturn("bar_schema");
return result;
}
}
diff --git
a/database/connector/dialect/presto/src/main/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoader.java
b/database/connector/dialect/presto/src/main/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoader.java
index aaa8d8c885d..e4bbe44d942 100644
---
a/database/connector/dialect/presto/src/main/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoader.java
+++
b/database/connector/dialect/presto/src/main/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoader.java
@@ -23,6 +23,7 @@ import
org.apache.shardingsphere.database.connector.core.metadata.data.model.Col
import
org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
import
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import
org.apache.shardingsphere.database.connector.core.metadata.database.datatype.DataTypeRegistry;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.enums.TableType;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -33,6 +34,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
@@ -45,23 +47,32 @@ import java.util.stream.Collectors;
*/
public final class PrestoMetaDataLoader implements DialectMetaDataLoader {
+ private static final String VIEW_META_DATA_SQL = "SELECT TABLE_NAME FROM
INFORMATION_SCHEMA.TABLES"
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND TABLE_TYPE='VIEW'
AND UPPER(TABLE_NAME) IN (%s)";
+
@Override
public Collection<SchemaMetaData> load(final MetaDataLoaderMaterial
material) throws SQLException {
Collection<TableMetaData> tableMetaDataList = new LinkedList<>();
try (Connection connection = material.getDataSource().getConnection())
{
- Map<String, Collection<ColumnMetaData>> columnMetaDataMap =
loadColumnMetaDataMap(connection, material.getActualTableNames());
+ String catalogName = connection.getCatalog();
+ String schemaName = connection.getSchema();
+ Map<String, Collection<ColumnMetaData>> columnMetaDataMap =
loadColumnMetaDataMap(connection, catalogName, schemaName,
material.getActualTableNames());
+ Collection<String> viewNames = columnMetaDataMap.isEmpty() ?
Collections.emptySet() : loadViewNames(connection, catalogName, schemaName,
columnMetaDataMap.keySet());
for (Entry<String, Collection<ColumnMetaData>> entry :
columnMetaDataMap.entrySet()) {
- tableMetaDataList.add(new TableMetaData(entry.getKey(),
entry.getValue(), Collections.emptyList(), Collections.emptyList()));
+ tableMetaDataList.add(new TableMetaData(
+ entry.getKey(), entry.getValue(),
Collections.emptyList(), Collections.emptyList(),
viewNames.contains(entry.getKey()) ? TableType.VIEW : TableType.TABLE));
}
}
return Collections.singleton(new
SchemaMetaData(material.getDefaultSchemaName(), tableMetaDataList));
}
@SuppressWarnings("CollectionWithoutInitialCapacity")
- private Map<String, Collection<ColumnMetaData>>
loadColumnMetaDataMap(final Connection connection, final Collection<String>
tables) throws SQLException {
+ private Map<String, Collection<ColumnMetaData>>
loadColumnMetaDataMap(final Connection connection, final String catalogName,
final String schemaName,
+
final Collection<String> tables) throws SQLException {
Map<String, Collection<ColumnMetaData>> result = new HashMap<>();
try (PreparedStatement preparedStatement =
connection.prepareStatement(getTableMetaDataSQL(tables))) {
- preparedStatement.setString(1, connection.getCatalog());
+ preparedStatement.setString(1, catalogName);
+ preparedStatement.setString(2, schemaName);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
String tableName = resultSet.getString("TABLE_NAME");
@@ -78,18 +89,43 @@ public final class PrestoMetaDataLoader implements
DialectMetaDataLoader {
private String getTableMetaDataSQL(final Collection<String> tables) {
if (tables.isEmpty()) {
- return "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG=? ORDER BY
ORDINAL_POSITION";
+ return "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS"
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? ORDER BY
ORDINAL_POSITION";
}
String tableNames = tables.stream().map(each -> String.format("'%s'",
each).toUpperCase()).collect(Collectors.joining(","));
return String.format("SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS"
- + " WHERE TABLE_CATALOG=? AND UPPER(TABLE_NAME) IN (%s) ORDER
BY ORDINAL_POSITION", tableNames);
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND
UPPER(TABLE_NAME) IN (%s) ORDER BY ORDINAL_POSITION", tableNames);
}
private ColumnMetaData loadColumnMetaData(final ResultSet resultSet)
throws SQLException {
String columnName = resultSet.getString("COLUMN_NAME");
String dataType = resultSet.getString("DATA_TYPE");
boolean isNullable = "YES".equals(resultSet.getString("IS_NULLABLE"));
- return new ColumnMetaData(columnName,
DataTypeRegistry.getDataType(getDatabaseType(), dataType).orElse(Types.OTHER),
Boolean.FALSE, Boolean.FALSE, false, Boolean.TRUE, false, isNullable);
+ return new ColumnMetaData(columnName,
DataTypeRegistry.getDataType(getDatabaseType(), dataType).orElse(Types.OTHER),
Boolean.FALSE, Boolean.FALSE,
+ isStringDataType(dataType), Boolean.TRUE, false, isNullable);
+ }
+
+ private boolean isStringDataType(final String dataType) {
+ String normalizedDataType = dataType.toLowerCase(Locale.ENGLISH);
+ return normalizedDataType.startsWith("varchar") ||
normalizedDataType.startsWith("char");
+ }
+
+ private Collection<String> loadViewNames(final Connection connection,
final String catalogName, final String schemaName, final Collection<String>
tableNames) throws SQLException {
+ Collection<String> result = new LinkedList<>();
+ try (PreparedStatement preparedStatement =
connection.prepareStatement(getViewMetaDataSQL(tableNames))) {
+ preparedStatement.setString(1, catalogName);
+ preparedStatement.setString(2, schemaName);
+ try (ResultSet resultSet = preparedStatement.executeQuery()) {
+ while (resultSet.next()) {
+ result.add(resultSet.getString("TABLE_NAME"));
+ }
+ }
+ }
+ return result;
+ }
+
+ private String getViewMetaDataSQL(final Collection<String> tableNames) {
+ return String.format(VIEW_META_DATA_SQL, tableNames.stream().map(each
-> String.format("'%s'",
each).toUpperCase(Locale.ENGLISH)).collect(Collectors.joining(",")));
}
@Override
diff --git
a/database/connector/dialect/presto/src/test/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoaderTest.java
b/database/connector/dialect/presto/src/test/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoaderTest.java
index 4ed0b0da152..86cebf8b746 100644
---
a/database/connector/dialect/presto/src/test/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoaderTest.java
+++
b/database/connector/dialect/presto/src/test/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoaderTest.java
@@ -23,6 +23,7 @@ import
org.apache.shardingsphere.database.connector.core.metadata.data.model.Col
import
org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
import
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import
org.apache.shardingsphere.database.connector.core.metadata.database.datatype.DataTypeRegistry;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.enums.TableType;
import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
@@ -47,6 +48,7 @@ import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(AutoMockExtension.class)
@@ -59,25 +61,34 @@ class PrestoMetaDataLoaderTest {
@Test
void assertLoadWithoutTableFilter() throws SQLException {
- Connection connectionWithoutTables = mockConnectionWithoutTables();
+ PreparedStatement columnMetaDataStatement =
mock(PreparedStatement.class);
+ PreparedStatement viewMetaDataStatement =
mock(PreparedStatement.class);
+ Connection connectionWithoutTables =
mockConnectionWithoutTables(columnMetaDataStatement, viewMetaDataStatement);
DataSource dataSource = mock(DataSource.class);
when(dataSource.getConnection()).thenReturn(connectionWithoutTables);
when(DataTypeRegistry.getDataType("Presto",
"int")).thenReturn(Optional.of(Types.INTEGER));
when(DataTypeRegistry.getDataType("Presto",
"varchar")).thenReturn(Optional.empty());
Collection<SchemaMetaData> actualWithoutTables = loader.load(new
MetaDataLoaderMaterial(Collections.emptyList(), "ds_0", dataSource,
databaseType, "def_schema"));
- SchemaMetaData schemaMetaDataWithoutTables =
actualWithoutTables.iterator().next();
- assertThat(schemaMetaDataWithoutTables.getName(), is("def_schema"));
- TableMetaData tableMetaDataWithoutTables =
schemaMetaDataWithoutTables.getTables().iterator().next();
- assertThat(tableMetaDataWithoutTables.getName(), is("tbl_one"));
- Iterator<ColumnMetaData> columnIterator =
tableMetaDataWithoutTables.getColumns().iterator();
- ColumnMetaData firstColumn = columnIterator.next();
- assertThat(firstColumn.getName(), is("id"));
- assertThat(firstColumn.getDataType(), is(Types.INTEGER));
- assertTrue(firstColumn.isNullable());
- ColumnMetaData secondColumn = columnIterator.next();
- assertThat(secondColumn.getName(), is("name"));
- assertThat(secondColumn.getDataType(), is(Types.OTHER));
- assertFalse(secondColumn.isNullable());
+ SchemaMetaData actualSchema = actualWithoutTables.iterator().next();
+ assertThat(actualSchema.getName(), is("def_schema"));
+ TableMetaData actualTable = actualSchema.getTables().iterator().next();
+ assertThat(actualTable.getName(), is("tbl_one"));
+ assertThat(actualTable.getType(), is(TableType.VIEW));
+ Iterator<ColumnMetaData> actualColumns =
actualTable.getColumns().iterator();
+ ColumnMetaData actualFirstColumn = actualColumns.next();
+ assertThat(actualFirstColumn.getName(), is("id"));
+ assertThat(actualFirstColumn.getDataType(), is(Types.INTEGER));
+ assertFalse(actualFirstColumn.isCaseSensitive());
+ assertTrue(actualFirstColumn.isNullable());
+ ColumnMetaData actualSecondColumn = actualColumns.next();
+ assertThat(actualSecondColumn.getName(), is("name"));
+ assertThat(actualSecondColumn.getDataType(), is(Types.OTHER));
+ assertTrue(actualSecondColumn.isCaseSensitive());
+ assertFalse(actualSecondColumn.isNullable());
+ verify(columnMetaDataStatement).setString(1, "catalog_one");
+ verify(columnMetaDataStatement).setString(2, "foo_schema");
+ verify(viewMetaDataStatement).setString(1, "catalog_one");
+ verify(viewMetaDataStatement).setString(2, "foo_schema");
}
@Test
@@ -87,21 +98,30 @@ class PrestoMetaDataLoaderTest {
when(dataSource.getConnection()).thenReturn(connectionWithTables);
when(DataTypeRegistry.getDataType("Presto",
"json")).thenReturn(Optional.of(Types.JAVA_OBJECT));
Collection<SchemaMetaData> actualWithTables = loader.load(new
MetaDataLoaderMaterial(Collections.singletonList("target_table"), "ds_0",
dataSource, databaseType, "def_schema"));
- SchemaMetaData schemaMetaDataWithTables =
actualWithTables.iterator().next();
- TableMetaData tableMetaDataWithTables =
schemaMetaDataWithTables.getTables().iterator().next();
- ColumnMetaData payloadColumn =
tableMetaDataWithTables.getColumns().iterator().next();
- assertThat(tableMetaDataWithTables.getName(), is("target_table"));
- assertThat(payloadColumn.getDataType(), is(Types.JAVA_OBJECT));
+ SchemaMetaData actualSchema = actualWithTables.iterator().next();
+ TableMetaData actualTable = actualSchema.getTables().iterator().next();
+ ColumnMetaData actualColumn =
actualTable.getColumns().iterator().next();
+ assertThat(actualTable.getName(), is("target_table"));
+ assertThat(actualTable.getType(), is(TableType.TABLE));
+ assertThat(actualColumn.getDataType(), is(Types.JAVA_OBJECT));
+ assertFalse(actualColumn.isCaseSensitive());
}
- private Connection mockConnectionWithoutTables() throws SQLException {
+ private Connection mockConnectionWithoutTables(final PreparedStatement
columnMetaDataStatement, final PreparedStatement viewMetaDataStatement) throws
SQLException {
Connection result = mock(Connection.class);
- PreparedStatement preparedStatement = mock(PreparedStatement.class);
ResultSet resultSet = mockResultSetWithoutTables();
- when(preparedStatement.executeQuery()).thenReturn(resultSet);
+ when(columnMetaDataStatement.executeQuery()).thenReturn(resultSet);
+ ResultSet viewResultSet = mock(ResultSet.class);
+ when(viewResultSet.next()).thenReturn(true, false);
+ when(viewResultSet.getString("TABLE_NAME")).thenReturn("tbl_one");
+ when(viewMetaDataStatement.executeQuery()).thenReturn(viewResultSet);
when(result.getCatalog()).thenReturn("catalog_one");
- String sql = "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG=? ORDER BY
ORDINAL_POSITION";
- when(result.prepareStatement(sql)).thenReturn(preparedStatement);
+ when(result.getSchema()).thenReturn("foo_schema");
+ String sql = "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS"
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? ORDER BY
ORDINAL_POSITION";
+ when(result.prepareStatement(sql)).thenReturn(columnMetaDataStatement);
+ String viewSql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND TABLE_TYPE='VIEW' AND
UPPER(TABLE_NAME) IN ('TBL_ONE')";
+
when(result.prepareStatement(viewSql)).thenReturn(viewMetaDataStatement);
return result;
}
@@ -117,13 +137,19 @@ class PrestoMetaDataLoaderTest {
private Connection mockConnectionWithTables() throws SQLException {
Connection result = mock(Connection.class);
- PreparedStatement preparedStatement = mock(PreparedStatement.class);
+ PreparedStatement columnMetaDataStatement =
mock(PreparedStatement.class);
ResultSet resultSet = mockResultSetWithTables();
- when(preparedStatement.executeQuery()).thenReturn(resultSet);
+ when(columnMetaDataStatement.executeQuery()).thenReturn(resultSet);
+ PreparedStatement viewMetaDataStatement =
mock(PreparedStatement.class);
+ ResultSet viewResultSet = mock(ResultSet.class);
+ when(viewMetaDataStatement.executeQuery()).thenReturn(viewResultSet);
String sql = "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS "
- + "WHERE TABLE_CATALOG=? AND UPPER(TABLE_NAME) IN
('TARGET_TABLE') ORDER BY ORDINAL_POSITION";
- when(result.prepareStatement(sql)).thenReturn(preparedStatement);
+ + "WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND
UPPER(TABLE_NAME) IN ('TARGET_TABLE') ORDER BY ORDINAL_POSITION";
+ when(result.prepareStatement(sql)).thenReturn(columnMetaDataStatement);
+ String viewSql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND TABLE_TYPE='VIEW' AND
UPPER(TABLE_NAME) IN ('TARGET_TABLE')";
+
when(result.prepareStatement(viewSql)).thenReturn(viewMetaDataStatement);
when(result.getCatalog()).thenReturn("catalog_two");
+ when(result.getSchema()).thenReturn("bar_schema");
return result;
}