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 <duanzhengqi...@apache.org>
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);

Reply via email to