This is an automated email from the ASF dual-hosted git repository.
tuichenchuxin 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 6e7f2628179 Fix class cast exception when select columns system table
(#30545)
6e7f2628179 is described below
commit 6e7f2628179639185bd91fbf2cf92afb95ede6d2
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Wed Mar 20 11:48:42 2024 +0800
Fix class cast exception when select columns system table (#30545)
* Fix class cast exception when select columns system table
* fix unit test
* fix MemoryEnumerator data type convert
---
.../sqlfederation/engine/SQLFederationEngine.java | 4 +-
.../enumerable/EnumerableScanExecutor.java | 8 +--
.../executor/row/MemoryEnumerator.java | 67 +++++++++++++++++++---
.../enumerable/EnumerableScanExecutorTest.java | 9 ++-
.../metadata/util/SQLFederationDataTypeUtils.java | 9 ++-
5 files changed, 80 insertions(+), 17 deletions(-)
diff --git
a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/engine/SQLFederationEngine.java
b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/engine/SQLFederationEngine.java
index 2215722a1ed..fb88e6d43fb 100644
---
a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/engine/SQLFederationEngine.java
+++
b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/engine/SQLFederationEngine.java
@@ -230,8 +230,8 @@ public final class SQLFederationEngine implements
AutoCloseable {
TableScanExecutorContext executorContext = new
TableScanExecutorContext(databaseName, schemaName, metaData.getProps(),
federationContext);
EnumerableScanExecutor scanExecutor = new
EnumerableScanExecutor(prepareEngine, jdbcExecutor, callback, optimizerContext,
metaData.getGlobalRuleMetaData(), executorContext, statistics);
// TODO register only the required tables
- for (String each :
metaData.getDatabase(databaseName).getSchema(schemaName).getAllTableNames()) {
- Table table = sqlFederationSchema.getTable(each);
+ for (ShardingSphereTable each :
metaData.getDatabase(databaseName).getSchema(schemaName).getTables().values()) {
+ Table table = sqlFederationSchema.getTable(each.getName());
if (table instanceof SQLFederationTable) {
((SQLFederationTable) table).setScanExecutor(scanExecutor);
}
diff --git
a/kernel/sql-federation/executor/src/main/java/org/apache/shardingsphere/sqlfederation/executor/enumerable/EnumerableScanExecutor.java
b/kernel/sql-federation/executor/src/main/java/org/apache/shardingsphere/sqlfederation/executor/enumerable/EnumerableScanExecutor.java
index d5937649280..fde84dcd9dc 100644
---
a/kernel/sql-federation/executor/src/main/java/org/apache/shardingsphere/sqlfederation/executor/enumerable/EnumerableScanExecutor.java
+++
b/kernel/sql-federation/executor/src/main/java/org/apache/shardingsphere/sqlfederation/executor/enumerable/EnumerableScanExecutor.java
@@ -181,11 +181,11 @@ public final class EnumerableScanExecutor implements
ScanExecutor {
private Enumerable<Object> executeByShardingSphereData(final String
databaseName, final String schemaName, final ShardingSphereTable table, final
DatabaseType databaseType) {
// TODO move this logic to ShardingSphere statistics
if (databaseType instanceof OpenGaussDatabaseType &&
SYSTEM_CATALOG_TABLES.contains(table.getName())) {
- return createMemoryEnumerator(createSystemCatalogTableData(table));
+ return createMemoryEnumerator(createSystemCatalogTableData(table),
table, databaseType);
}
Optional<ShardingSphereTableData> tableData =
Optional.ofNullable(statistics.getDatabaseData().get(databaseName)).map(optional
-> optional.getSchemaData().get(schemaName))
.map(ShardingSphereSchemaData::getTableData).map(shardingSphereData ->
shardingSphereData.get(table.getName()));
- return
tableData.map(this::createMemoryEnumerator).orElseGet(this::createEmptyEnumerable);
+ return tableData.map(optional -> createMemoryEnumerator(optional,
table, databaseType)).orElseGet(this::createEmptyEnumerable);
}
private ShardingSphereTableData createSystemCatalogTableData(final
ShardingSphereTable table) {
@@ -231,12 +231,12 @@ public final class EnumerableScanExecutor implements
ScanExecutor {
}
}
- private Enumerable<Object> createMemoryEnumerator(final
ShardingSphereTableData tableData) {
+ private Enumerable<Object> createMemoryEnumerator(final
ShardingSphereTableData tableData, final ShardingSphereTable table, final
DatabaseType databaseType) {
return new AbstractEnumerable<Object>() {
@Override
public Enumerator<Object> enumerator() {
- return new MemoryEnumerator(tableData.getRows());
+ return new MemoryEnumerator(tableData.getRows(),
table.getColumns().values(), databaseType);
}
};
}
diff --git
a/kernel/sql-federation/executor/src/main/java/org/apache/shardingsphere/sqlfederation/executor/row/MemoryEnumerator.java
b/kernel/sql-federation/executor/src/main/java/org/apache/shardingsphere/sqlfederation/executor/row/MemoryEnumerator.java
index f37b3477520..889b8bfd566 100644
---
a/kernel/sql-federation/executor/src/main/java/org/apache/shardingsphere/sqlfederation/executor/row/MemoryEnumerator.java
+++
b/kernel/sql-federation/executor/src/main/java/org/apache/shardingsphere/sqlfederation/executor/row/MemoryEnumerator.java
@@ -17,11 +17,22 @@
package org.apache.shardingsphere.sqlfederation.executor.row;
+import lombok.SneakyThrows;
import org.apache.calcite.linq4j.Enumerator;
+import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
+import
org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.util.ResultSetUtils;
+import
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
import
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereRowData;
+import
org.apache.shardingsphere.sqlfederation.optimizer.metadata.util.SQLFederationDataTypeUtils;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
/**
* Memory enumerator.
@@ -30,13 +41,36 @@ public final class MemoryEnumerator implements
Enumerator<Object> {
private final Collection<ShardingSphereRowData> rows;
- private Iterator<ShardingSphereRowData> rowDataIterator;
+ private final DatabaseType databaseType;
+
+ private final Map<Integer, Class<?>> columnTypes;
+
+ private Iterator<ShardingSphereRowData> iterator;
private Object current;
- public MemoryEnumerator(final Collection<ShardingSphereRowData> rows) {
+ public MemoryEnumerator(final Collection<ShardingSphereRowData> rows,
final Collection<ShardingSphereColumn> columns, final DatabaseType
databaseType) {
this.rows = rows;
- rowDataIterator = rows.iterator();
+ this.databaseType = databaseType;
+ columnTypes = createColumnTypes(new ArrayList<>(columns));
+ iterator = rows.iterator();
+ }
+
+ private Map<Integer, Class<?>> createColumnTypes(final
List<ShardingSphereColumn> columns) {
+ Map<Integer, Class<?>> result = new HashMap<>(columns.size(), 1F);
+ for (int index = 0; index < columns.size(); index++) {
+ int finalIndex = index;
+ getSqlTypeClass(columns, index).ifPresent(optional ->
result.put(finalIndex, optional));
+ }
+ return result;
+ }
+
+ private Optional<Class<?>> getSqlTypeClass(final
List<ShardingSphereColumn> columns, final int index) {
+ try {
+ return
Optional.of(SQLFederationDataTypeUtils.getSqlTypeClass(databaseType,
columns.get(index)));
+ } catch (final IllegalArgumentException ex) {
+ return Optional.empty();
+ }
}
@Override
@@ -46,22 +80,41 @@ public final class MemoryEnumerator implements
Enumerator<Object> {
@Override
public boolean moveNext() {
- if (rowDataIterator.hasNext()) {
- current = rowDataIterator.next().getRows().toArray();
+ if (iterator.hasNext()) {
+ current = convertToTargetType(iterator.next().getRows().toArray());
return true;
}
current = null;
- rowDataIterator = rows.iterator();
+ iterator = rows.iterator();
return false;
}
+ @SneakyThrows
+ private Object[] convertToTargetType(final Object[] rows) {
+ Object[] result = new Object[rows.length];
+ for (int index = 0; index < rows.length; index++) {
+ if (columnTypes.containsKey(index)) {
+ result[index] = convertValue(rows, index);
+ }
+ }
+ return result;
+ }
+
+ private Object convertValue(final Object[] rows, final int index) {
+ try {
+ return ResultSetUtils.convertValue(rows[index],
columnTypes.get(index));
+ } catch (final SQLFeatureNotSupportedException ex) {
+ return rows[index];
+ }
+ }
+
@Override
public void reset() {
}
@Override
public void close() {
- rowDataIterator = rows.iterator();
+ iterator = rows.iterator();
current = null;
}
}
diff --git
a/kernel/sql-federation/executor/src/test/java/org/apache/shardingsphere/sqlfederation/executor/enumerable/EnumerableScanExecutorTest.java
b/kernel/sql-federation/executor/src/test/java/org/apache/shardingsphere/sqlfederation/executor/enumerable/EnumerableScanExecutorTest.java
index 727cb707374..d258e1a4ece 100644
---
a/kernel/sql-federation/executor/src/test/java/org/apache/shardingsphere/sqlfederation/executor/enumerable/EnumerableScanExecutorTest.java
+++
b/kernel/sql-federation/executor/src/test/java/org/apache/shardingsphere/sqlfederation/executor/enumerable/EnumerableScanExecutorTest.java
@@ -20,6 +20,7 @@ package
org.apache.shardingsphere.sqlfederation.executor.enumerable;
import org.apache.calcite.linq4j.Enumerable;
import org.apache.calcite.linq4j.Enumerator;
import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
+import
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
import
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
import
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereDatabaseData;
import
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereRowData;
@@ -32,6 +33,7 @@ import
org.apache.shardingsphere.sqlfederation.optimizer.context.OptimizerContex
import
org.apache.shardingsphere.sqlfederation.optimizer.metadata.schema.table.ScanExecutorContext;
import org.junit.jupiter.api.Test;
+import java.sql.Types;
import java.util.Collections;
import static org.hamcrest.CoreMatchers.instanceOf;
@@ -59,10 +61,11 @@ class EnumerableScanExecutorTest {
ShardingSphereTableData tableData =
mock(ShardingSphereTableData.class);
when(tableData.getRows()).thenReturn(Collections.singletonList(new
ShardingSphereRowData(Collections.singletonList(1))));
when(schemaData.getTableData().get("test")).thenReturn(tableData);
- ShardingSphereTable shardingSphereTable =
mock(ShardingSphereTable.class);
- when(shardingSphereTable.getName()).thenReturn("test");
+ ShardingSphereTable table = mock(ShardingSphereTable.class,
RETURNS_DEEP_STUBS);
+ when(table.getName()).thenReturn("test");
+ when(table.getColumns().values()).thenReturn(Collections.singleton(new
ShardingSphereColumn("id", Types.INTEGER, true, false, false, false, true,
false)));
Enumerable<Object> enumerable = new EnumerableScanExecutor(null, null,
null, optimizerContext, null, executorContext, statistics)
- .execute(shardingSphereTable, mock(ScanExecutorContext.class));
+ .execute(table, mock(ScanExecutorContext.class));
try (Enumerator<Object> actual = enumerable.enumerator()) {
actual.moveNext();
Object row = actual.current();
diff --git
a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/metadata/util/SQLFederationDataTypeUtils.java
b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/metadata/util/SQLFederationDataTypeUtils.java
index 4fd4846f597..c5e067150df 100644
---
a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/metadata/util/SQLFederationDataTypeUtils.java
+++
b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/metadata/util/SQLFederationDataTypeUtils.java
@@ -62,7 +62,14 @@ public final class SQLFederationDataTypeUtils {
return typeFactory.createTypeWithNullability(javaType, true);
}
- private static Class<?> getSqlTypeClass(final DatabaseType protocolType,
final ShardingSphereColumn column) {
+ /**
+ * Get SQL type class.
+ *
+ * @param protocolType protocol type
+ * @param column ShardingSphere column
+ * @return SQL type class
+ */
+ public static Class<?> getSqlTypeClass(final DatabaseType protocolType,
final ShardingSphereColumn column) {
Optional<Class<?>> typeClazz = Optional.empty();
if (protocolType instanceof MySQLDatabaseType) {
typeClazz = findMySQLTypeClass(column);