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

zykkk pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.1 by this push:
     new 104284bd6f4 [Refactor](jdbc catalog) Enhance Field Handling in 
JdbcFieldSchema Using Optional for Better Null Safety (#34730)
104284bd6f4 is described below

commit 104284bd6f4d0aa815b09abefce463182665a5cc
Author: zy-kkk <[email protected]>
AuthorDate: Mon May 13 22:37:35 2024 +0800

    [Refactor](jdbc catalog) Enhance Field Handling in JdbcFieldSchema Using 
Optional for Better Null Safety (#34730)
    
    In some cases, using Resultset.getxxx cannot correctly handle null data, so 
I use Optional to enhance the fields of JdbcFieldSchema for better type mapping 
when some results are null.
---
 .../hive/PostgreSQLJdbcHMSCachedClient.java        |  1 +
 .../jdbc/client/JdbcClickHouseClient.java          |  7 +-
 .../doris/datasource/jdbc/client/JdbcClient.java   | 55 +------------
 .../datasource/jdbc/client/JdbcDB2Client.java      | 13 ++--
 .../datasource/jdbc/client/JdbcMySQLClient.java    | 60 +++++---------
 .../jdbc/client/JdbcOceanBaseClient.java           |  1 +
 .../datasource/jdbc/client/JdbcOracleClient.java   | 31 ++------
 .../jdbc/client/JdbcPostgreSQLClient.java          | 13 ++--
 .../jdbc/client/JdbcSQLServerClient.java           |  9 ++-
 .../datasource/jdbc/client/JdbcSapHanaClient.java  | 17 ++--
 .../datasource/jdbc/client/JdbcTrinoClient.java    | 11 ++-
 .../datasource/jdbc/util/JdbcFieldSchema.java      | 91 ++++++++++++++++++++++
 12 files changed, 165 insertions(+), 144 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/PostgreSQLJdbcHMSCachedClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/PostgreSQLJdbcHMSCachedClient.java
index a0c2aa29ab5..932118001e5 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/PostgreSQLJdbcHMSCachedClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/PostgreSQLJdbcHMSCachedClient.java
@@ -24,6 +24,7 @@ import org.apache.doris.datasource.DatabaseMetadata;
 import org.apache.doris.datasource.TableMetadata;
 import 
org.apache.doris.datasource.hive.event.MetastoreNotificationFetchException;
 import org.apache.doris.datasource.jdbc.client.JdbcClientConfig;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 import org.apache.doris.thrift.TOdbcTableType;
 
 import com.google.common.base.Joiner;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java
index 35e6c83af1f..bdf0cbbc934 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java
@@ -20,6 +20,9 @@ package org.apache.doris.datasource.jdbc.client;
 import org.apache.doris.catalog.ArrayType;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
+
+import java.util.Optional;
 
 public class JdbcClickHouseClient extends JdbcClient {
 
@@ -35,7 +38,7 @@ public class JdbcClickHouseClient extends JdbcClient {
     @Override
     protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) {
 
-        String ckType = fieldSchema.getDataTypeName();
+        String ckType = fieldSchema.getDataTypeName().orElse("unknown");
 
         if (ckType.startsWith("LowCardinality")) {
             fieldSchema.setAllowNull(true);
@@ -81,7 +84,7 @@ public class JdbcClickHouseClient extends JdbcClient {
 
         if (ckType.startsWith("Array")) {
             String cktype = ckType.substring(6, ckType.length() - 1);
-            fieldSchema.setDataTypeName(cktype);
+            fieldSchema.setDataTypeName(Optional.of(cktype));
             Type type = jdbcTypeToDoris(fieldSchema);
             return ArrayType.create(type, true);
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClient.java
index 604e54277f1..0ae2966079c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClient.java
@@ -24,11 +24,11 @@ import org.apache.doris.catalog.Type;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.util.Util;
 import org.apache.doris.datasource.jdbc.JdbcIdentifierMapping;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.zaxxer.hikari.HikariDataSource;
-import lombok.Data;
 import lombok.Getter;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -255,14 +255,7 @@ public abstract class JdbcClient {
     public List<JdbcFieldSchema> 
getSchemaFromResultSetMetaData(ResultSetMetaData metaData) throws SQLException {
         List<JdbcFieldSchema> schemas = Lists.newArrayList();
         for (int i = 1; i <= metaData.getColumnCount(); i++) {
-            JdbcFieldSchema field = new JdbcFieldSchema();
-            field.setColumnName(metaData.getColumnName(i));
-            field.setDataType(metaData.getColumnType(i));
-            field.setDataTypeName(metaData.getColumnTypeName(i));
-            field.setColumnSize(metaData.getColumnDisplaySize(i));
-            field.setDecimalDigits(metaData.getScale(i));
-            field.setNumPrecRadix(metaData.getPrecision(i));
-            schemas.add(field);
+            schemas.add(new JdbcFieldSchema(metaData, i));
         }
         return schemas;
     }
@@ -347,27 +340,7 @@ public abstract class JdbcClient {
             String catalogName = getCatalogName(conn);
             rs = getRemoteColumns(databaseMetaData, catalogName, remoteDbName, 
remoteTableName);
             while (rs.next()) {
-                JdbcFieldSchema field = new JdbcFieldSchema();
-                field.setColumnName(rs.getString("COLUMN_NAME"));
-                field.setDataType(rs.getInt("DATA_TYPE"));
-                field.setDataTypeName(rs.getString("TYPE_NAME"));
-                /*
-                   We used this method to retrieve the key column of the JDBC 
table, but since we only tested mysql,
-                   we kept the default key behavior in the parent class and 
only overwrite it in the mysql subclass
-                */
-                field.setColumnSize(rs.getInt("COLUMN_SIZE"));
-                field.setDecimalDigits(rs.getInt("DECIMAL_DIGITS"));
-                field.setNumPrecRadix(rs.getInt("NUM_PREC_RADIX"));
-                /*
-                   Whether it is allowed to be NULL
-                   0 (columnNoNulls)
-                   1 (columnNullable)
-                   2 (columnNullableUnknown)
-                 */
-                field.setAllowNull(rs.getInt("NULLABLE") != 0);
-                field.setRemarks(rs.getString("REMARKS"));
-                field.setCharOctetLength(rs.getInt("CHAR_OCTET_LENGTH"));
-                tableSchema.add(field);
+                tableSchema.add(new JdbcFieldSchema(rs));
             }
         } catch (SQLException e) {
             throw new JdbcClientException("failed to get jdbc columns info for 
remote table `%s.%s`: %s",
@@ -478,28 +451,6 @@ public abstract class JdbcClient {
         return jdbcLowerCaseMetaMatching.setColumnNameMapping(remoteDbName, 
remoteTableName, remoteColumns);
     }
 
-    @Data
-    protected static class JdbcFieldSchema {
-        protected String columnName;
-        // The SQL type of the corresponding java.sql.types (Type ID)
-        protected int dataType;
-        // The SQL type of the corresponding java.sql.types (Type Name)
-        protected String dataTypeName;
-        // For CHAR/DATA, columnSize means the maximum number of chars.
-        // For NUMERIC/DECIMAL, columnSize means precision.
-        protected int columnSize;
-        protected int decimalDigits;
-        // Base number (usually 10 or 2)
-        protected int numPrecRadix;
-        // column description
-        protected String remarks;
-        // This length is the maximum number of bytes for CHAR type
-        // for utf8 encoding, if columnSize=10, then charOctetLength=30
-        // because for utf8 encoding, a Chinese character takes up 3 bytes
-        protected int charOctetLength;
-        protected boolean isAllowNull;
-    }
-
     protected abstract Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema);
 
     protected Type createDecimalOrStringType(int precision, int scale) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcDB2Client.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcDB2Client.java
index af89f33eb9a..dafb00ca9e8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcDB2Client.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcDB2Client.java
@@ -20,6 +20,7 @@ package org.apache.doris.datasource.jdbc.client;
 import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 
 import com.google.common.collect.Lists;
 
@@ -63,7 +64,7 @@ public class JdbcDB2Client extends JdbcClient {
 
     @Override
     protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) {
-        String db2Type = fieldSchema.getDataTypeName();
+        String db2Type = fieldSchema.getDataTypeName().orElse("unknown");
         switch (db2Type) {
             case "SMALLINT":
                 return Type.SMALLINT;
@@ -73,8 +74,8 @@ public class JdbcDB2Client extends JdbcClient {
                 return Type.BIGINT;
             case "DECFLOAT":
             case "DECIMAL": {
-                int precision = fieldSchema.getColumnSize();
-                int scale = fieldSchema.getDecimalDigits();
+                int precision = fieldSchema.getColumnSize().orElse(0);
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 return createDecimalOrStringType(precision, scale);
             }
             case "DOUBLE":
@@ -83,18 +84,18 @@ public class JdbcDB2Client extends JdbcClient {
                 return Type.FLOAT;
             case "CHAR":
                 ScalarType charType = 
ScalarType.createType(PrimitiveType.CHAR);
-                charType.setLength(fieldSchema.columnSize);
+                charType.setLength(fieldSchema.getColumnSize().orElse(0));
                 return charType;
             case "VARCHAR":
             case "LONG VARCHAR":
                 ScalarType varcharType = 
ScalarType.createType(PrimitiveType.VARCHAR);
-                varcharType.setLength(fieldSchema.columnSize);
+                varcharType.setLength(fieldSchema.getColumnSize().orElse(0));
                 return varcharType;
             case "DATE":
                 return ScalarType.createDateV2Type();
             case "TIMESTAMP": {
                 // postgres can support microsecond
-                int scale = fieldSchema.getDecimalDigits();
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 if (scale > 6) {
                     scale = 6;
                 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java
index 6ea5ea127d5..eee254482d2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java
@@ -22,6 +22,7 @@ import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
 import org.apache.doris.common.util.Util;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
@@ -122,40 +123,21 @@ public class JdbcMySQLClient extends JdbcClient {
     public List<JdbcFieldSchema> getJdbcColumnsInfo(String localDbName, String 
localTableName) {
         Connection conn = getConnection();
         ResultSet rs = null;
-        List<JdbcFieldSchema> tableSchema = 
com.google.common.collect.Lists.newArrayList();
+        List<JdbcFieldSchema> tableSchema = Lists.newArrayList();
         String remoteDbName = getRemoteDatabaseName(localDbName);
         String remoteTableName = getRemoteTableName(localDbName, 
localTableName);
         try {
             DatabaseMetaData databaseMetaData = conn.getMetaData();
             String catalogName = getCatalogName(conn);
             rs = getRemoteColumns(databaseMetaData, catalogName, remoteDbName, 
remoteTableName);
-            Map<String, String> mapFieldtoType = null;
-            while (rs.next()) {
-                JdbcFieldSchema field = new JdbcFieldSchema();
-                field.setColumnName(rs.getString("COLUMN_NAME"));
-                field.setDataType(rs.getInt("DATA_TYPE"));
 
-                // in mysql-jdbc-connector-8.0.*, TYPE_NAME of the HLL column 
in doris will be "UNKNOWN"
-                // in mysql-jdbc-connector-5.1.*, TYPE_NAME of the HLL column 
in doris will be "HLL"
-                // in mysql-jdbc-connector-8.0.*, TYPE_NAME of BITMAP column 
in doris will be "BIT"
-                // in mysql-jdbc-connector-5.1.*, TYPE_NAME of BITMAP column 
in doris will be "BITMAP"
-                field.setDataTypeName(rs.getString("TYPE_NAME"));
-                if (isDoris) {
-                    mapFieldtoType = getColumnsDataTypeUseQuery(remoteDbName, 
remoteTableName);
-                    
field.setDataTypeName(mapFieldtoType.get(rs.getString("COLUMN_NAME")));
-                }
-                field.setColumnSize(rs.getInt("COLUMN_SIZE"));
-                field.setDecimalDigits(rs.getInt("DECIMAL_DIGITS"));
-                field.setNumPrecRadix(rs.getInt("NUM_PREC_RADIX"));
-                /*
-                   Whether it is allowed to be NULL
-                   0 (columnNoNulls)
-                   1 (columnNullable)
-                   2 (columnNullableUnknown)
-                 */
-                field.setAllowNull(rs.getInt("NULLABLE") != 0);
-                field.setRemarks(rs.getString("REMARKS"));
-                field.setCharOctetLength(rs.getInt("CHAR_OCTET_LENGTH"));
+            Map<String, String> mapFieldtoType = Maps.newHashMap();
+            if (isDoris) {
+                mapFieldtoType = getColumnsDataTypeUseQuery(remoteDbName, 
remoteTableName);
+            }
+
+            while (rs.next()) {
+                JdbcFieldSchema field = new JdbcFieldSchema(rs, 
mapFieldtoType);
                 tableSchema.add(field);
             }
         } catch (SQLException e) {
@@ -184,12 +166,12 @@ public class JdbcMySQLClient extends JdbcClient {
     protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) {
         // For Doris type
         if (isDoris) {
-            return 
dorisTypeToDoris(fieldSchema.getDataTypeName().toUpperCase());
+            return 
dorisTypeToDoris(fieldSchema.getDataTypeName().orElse("unknown").toUpperCase());
         }
         // For mysql type: "INT UNSIGNED":
-        // fieldSchema.getDataTypeName().split(" ")[0] == "INT"
-        // fieldSchema.getDataTypeName().split(" ")[1] == "UNSIGNED"
-        String[] typeFields = fieldSchema.getDataTypeName().split(" ");
+        // fieldSchema.getDataTypeName().orElse("unknown").split(" ")[0] == 
"INT"
+        // fieldSchema.getDataTypeName().orElse("unknown").split(" ")[1] == 
"UNSIGNED"
+        String[] typeFields = 
fieldSchema.getDataTypeName().orElse("unknown").split(" ");
         String mysqlType = typeFields[0];
         // For unsigned int, should extend the type.
         if (typeFields.length > 1 && "UNSIGNED".equals(typeFields[1])) {
@@ -204,8 +186,8 @@ public class JdbcMySQLClient extends JdbcClient {
                 case "BIGINT":
                     return Type.LARGEINT;
                 case "DECIMAL": {
-                    int precision = fieldSchema.getColumnSize() + 1;
-                    int scale = fieldSchema.getDecimalDigits();
+                    int precision = fieldSchema.getColumnSize().orElse(0) + 1;
+                    int scale = fieldSchema.getDecimalDigits().orElse(0);
                     return createDecimalOrStringType(precision, scale);
                 }
                 case "DOUBLE":
@@ -242,7 +224,7 @@ public class JdbcMySQLClient extends JdbcClient {
             case "DATETIME": {
                 // mysql can support microsecond
                 // use columnSize to calculate the precision of 
timestamp/datetime
-                int columnSize = fieldSchema.getColumnSize();
+                int columnSize = fieldSchema.getColumnSize().orElse(0);
                 int scale = columnSize > 19 ? columnSize - 20 : 0;
                 if (scale > 6) {
                     scale = 6;
@@ -257,18 +239,18 @@ public class JdbcMySQLClient extends JdbcClient {
             case "DOUBLE":
                 return Type.DOUBLE;
             case "DECIMAL": {
-                int precision = fieldSchema.getColumnSize();
-                int scale = fieldSchema.getDecimalDigits();
+                int precision = fieldSchema.getColumnSize().orElse(0);
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 return createDecimalOrStringType(precision, scale);
             }
             case "CHAR":
                 ScalarType charType = 
ScalarType.createType(PrimitiveType.CHAR);
-                charType.setLength(fieldSchema.columnSize);
+                charType.setLength(fieldSchema.getColumnSize().orElse(0));
                 return charType;
             case "VARCHAR":
-                return ScalarType.createVarcharType(fieldSchema.columnSize);
+                return 
ScalarType.createVarcharType(fieldSchema.getColumnSize().orElse(0));
             case "BIT":
-                if (fieldSchema.getColumnSize() == 1) {
+                if (fieldSchema.getColumnSize().orElse(0) == 1) {
                     return Type.BOOLEAN;
                 } else {
                     return ScalarType.createStringType();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcOceanBaseClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcOceanBaseClient.java
index 8628d62d70e..b8c5b61aea4 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcOceanBaseClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcOceanBaseClient.java
@@ -19,6 +19,7 @@ package org.apache.doris.datasource.jdbc.client;
 
 import org.apache.doris.catalog.JdbcResource;
 import org.apache.doris.catalog.Type;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcOracleClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcOracleClient.java
index 484028ed92e..0efa94d9bff 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcOracleClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcOracleClient.java
@@ -20,6 +20,7 @@ package org.apache.doris.datasource.jdbc.client;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
 import org.apache.doris.common.util.Util;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
@@ -69,27 +70,7 @@ public class JdbcOracleClient extends JdbcClient {
                 if (isModify && isTableModified(rs.getString("TABLE_NAME"), 
remoteTableName)) {
                     continue;
                 }
-                JdbcFieldSchema field = new JdbcFieldSchema();
-                field.setColumnName(rs.getString("COLUMN_NAME"));
-                field.setDataType(rs.getInt("DATA_TYPE"));
-                field.setDataTypeName(rs.getString("TYPE_NAME"));
-                /*
-                   We used this method to retrieve the key column of the JDBC 
table, but since we only tested mysql,
-                   we kept the default key behavior in the parent class and 
only overwrite it in the mysql subclass
-                */
-                field.setColumnSize(rs.getInt("COLUMN_SIZE"));
-                field.setDecimalDigits(rs.getInt("DECIMAL_DIGITS"));
-                field.setNumPrecRadix(rs.getInt("NUM_PREC_RADIX"));
-                /*
-                   Whether it is allowed to be NULL
-                   0 (columnNoNulls)
-                   1 (columnNullable)
-                   2 (columnNullableUnknown)
-                 */
-                field.setAllowNull(rs.getInt("NULLABLE") != 0);
-                field.setRemarks(rs.getString("REMARKS"));
-                field.setCharOctetLength(rs.getInt("CHAR_OCTET_LENGTH"));
-                tableSchema.add(field);
+                tableSchema.add(new JdbcFieldSchema(rs));
             }
         } catch (SQLException e) {
             throw new JdbcClientException("failed to get table name list from 
jdbc for table %s:%s", e, remoteTableName,
@@ -126,7 +107,7 @@ public class JdbcOracleClient extends JdbcClient {
 
     @Override
     protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) {
-        String oracleType = fieldSchema.getDataTypeName();
+        String oracleType = fieldSchema.getDataTypeName().orElse("unknown");
         if (oracleType.startsWith("INTERVAL")) {
             oracleType = oracleType.substring(0, 8);
         } else if (oracleType.startsWith("TIMESTAMP")) {
@@ -134,7 +115,7 @@ public class JdbcOracleClient extends JdbcClient {
                 return Type.UNSUPPORTED;
             }
             // oracle can support nanosecond, will lose precision
-            int scale = fieldSchema.getDecimalDigits();
+            int scale = fieldSchema.getDecimalDigits().orElse(0);
             if (scale > 6) {
                 scale = 6;
             }
@@ -160,8 +141,8 @@ public class JdbcOracleClient extends JdbcClient {
              *    In this case, doris can not determine p and s, so doris can 
not determine data type.
              */
             case "NUMBER":
-                int precision = fieldSchema.getColumnSize();
-                int scale = fieldSchema.getDecimalDigits();
+                int precision = fieldSchema.getColumnSize().orElse(0);
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 if (scale <= 0) {
                     precision -= scale;
                     if (precision < 3) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcPostgreSQLClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcPostgreSQLClient.java
index 3d0bbc4e561..e6694ffdc67 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcPostgreSQLClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcPostgreSQLClient.java
@@ -20,6 +20,7 @@ package org.apache.doris.datasource.jdbc.client;
 import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 
 public class JdbcPostgreSQLClient extends JdbcClient {
 
@@ -34,7 +35,7 @@ public class JdbcPostgreSQLClient extends JdbcClient {
 
     @Override
     protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) {
-        String pgType = fieldSchema.getDataTypeName();
+        String pgType = fieldSchema.getDataTypeName().orElse("unknown");
         switch (pgType) {
             case "int2":
             case "smallserial":
@@ -46,8 +47,8 @@ public class JdbcPostgreSQLClient extends JdbcClient {
             case "bigserial":
                 return Type.BIGINT;
             case "numeric": {
-                int precision = fieldSchema.getColumnSize();
-                int scale = fieldSchema.getDecimalDigits();
+                int precision = fieldSchema.getColumnSize().orElse(0);
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 return createDecimalOrStringType(precision, scale);
             }
             case "float4":
@@ -56,12 +57,12 @@ public class JdbcPostgreSQLClient extends JdbcClient {
                 return Type.DOUBLE;
             case "bpchar":
                 ScalarType charType = 
ScalarType.createType(PrimitiveType.CHAR);
-                charType.setLength(fieldSchema.columnSize);
+                charType.setLength(fieldSchema.getColumnSize().orElse(0));
                 return charType;
             case "timestamp":
             case "timestamptz": {
                 // postgres can support microsecond
-                int scale = fieldSchema.getDecimalDigits();
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 if (scale > 6) {
                     scale = 6;
                 }
@@ -72,7 +73,7 @@ public class JdbcPostgreSQLClient extends JdbcClient {
             case "bool":
                 return Type.BOOLEAN;
             case "bit":
-                if (fieldSchema.getColumnSize() == 1) {
+                if (fieldSchema.getColumnSize().orElse(0) == 1) {
                     return Type.BOOLEAN;
                 } else {
                     return ScalarType.createStringType();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcSQLServerClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcSQLServerClient.java
index e3d96421a13..1bb3ece7f09 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcSQLServerClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcSQLServerClient.java
@@ -19,6 +19,7 @@ package org.apache.doris.datasource.jdbc.client;
 
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 
 public class JdbcSQLServerClient extends JdbcClient {
 
@@ -28,7 +29,7 @@ public class JdbcSQLServerClient extends JdbcClient {
 
     @Override
     protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) {
-        String originSqlserverType = fieldSchema.getDataTypeName();
+        String originSqlserverType = 
fieldSchema.getDataTypeName().orElse("unknown");
         // For sqlserver IDENTITY type, such as 'INT IDENTITY'
         // originSqlserverType is "int identity", so we only get "int".
         String sqlserverType = originSqlserverType.split(" ")[0];
@@ -52,8 +53,8 @@ public class JdbcSQLServerClient extends JdbcClient {
                 return ScalarType.createDecimalV3Type(10, 4);
             case "decimal":
             case "numeric": {
-                int precision = fieldSchema.getColumnSize();
-                int scale = fieldSchema.getDecimalDigits();
+                int precision = fieldSchema.getColumnSize().orElse(0);
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 return ScalarType.createDecimalV3Type(precision, scale);
             }
             case "date":
@@ -62,7 +63,7 @@ public class JdbcSQLServerClient extends JdbcClient {
             case "datetime2":
             case "smalldatetime": {
                 // postgres can support microsecond
-                int scale = fieldSchema.getDecimalDigits();
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 if (scale > 6) {
                     scale = 6;
                 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcSapHanaClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcSapHanaClient.java
index 34dde63c806..f10d082bada 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcSapHanaClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcSapHanaClient.java
@@ -20,6 +20,7 @@ package org.apache.doris.datasource.jdbc.client;
 import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
 
 public class JdbcSapHanaClient extends JdbcClient {
     protected JdbcSapHanaClient(JdbcClientConfig jdbcClientConfig) {
@@ -38,7 +39,7 @@ public class JdbcSapHanaClient extends JdbcClient {
 
     @Override
     protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) {
-        String hanaType = fieldSchema.getDataTypeName();
+        String hanaType = fieldSchema.getDataTypeName().orElse("unknown");
         switch (hanaType) {
             case "TINYINT":
                 return Type.TINYINT;
@@ -50,9 +51,13 @@ public class JdbcSapHanaClient extends JdbcClient {
                 return Type.BIGINT;
             case "SMALLDECIMAL":
             case "DECIMAL": {
-                int precision = fieldSchema.getColumnSize();
-                int scale = fieldSchema.getDecimalDigits();
-                return createDecimalOrStringType(precision, scale);
+                if (!fieldSchema.getDecimalDigits().isPresent()) {
+                    return Type.DOUBLE;
+                } else  {
+                    int precision = fieldSchema.getColumnSize().orElse(0);
+                    int scale = fieldSchema.getDecimalDigits().orElse(0);
+                    return createDecimalOrStringType(precision, scale);
+                }
             }
             case "REAL":
                 return Type.FLOAT;
@@ -60,7 +65,7 @@ public class JdbcSapHanaClient extends JdbcClient {
                 return Type.DOUBLE;
             case "TIMESTAMP": {
                 // postgres can support microsecond
-                int scale = fieldSchema.getDecimalDigits();
+                int scale = fieldSchema.getDecimalDigits().orElse(0);
                 if (scale > 6) {
                     scale = 6;
                 }
@@ -76,7 +81,7 @@ public class JdbcSapHanaClient extends JdbcClient {
             case "CHAR":
             case "NCHAR":
                 ScalarType charType = 
ScalarType.createType(PrimitiveType.CHAR);
-                charType.setLength(fieldSchema.columnSize);
+                charType.setLength(fieldSchema.getColumnSize().orElse(0));
                 return charType;
             case "TIME":
             case "VARCHAR":
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcTrinoClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcTrinoClient.java
index e922254dbc0..006bf5a44f9 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcTrinoClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcTrinoClient.java
@@ -21,6 +21,9 @@ import org.apache.doris.catalog.ArrayType;
 import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
+import org.apache.doris.datasource.jdbc.util.JdbcFieldSchema;
+
+import java.util.Optional;
 
 public class JdbcTrinoClient extends JdbcClient {
     protected JdbcTrinoClient(JdbcClientConfig jdbcClientConfig) {
@@ -29,7 +32,7 @@ public class JdbcTrinoClient extends JdbcClient {
 
     @Override
     protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) {
-        String trinoType = fieldSchema.getDataTypeName();
+        String trinoType = fieldSchema.getDataTypeName().orElse("unknown");
         switch (trinoType) {
             case "integer":
                 return Type.INT;
@@ -61,12 +64,12 @@ public class JdbcTrinoClient extends JdbcClient {
 
         if (trinoType.startsWith("char")) {
             ScalarType charType = ScalarType.createType(PrimitiveType.CHAR);
-            charType.setLength(fieldSchema.columnSize);
+            charType.setLength(fieldSchema.getColumnSize().orElse(0));
             return charType;
         }
 
         if (trinoType.startsWith("timestamp")) {
-            int scale = fieldSchema.getDecimalDigits();
+            int scale = fieldSchema.getDecimalDigits().orElse(0);
             if (scale > 6) {
                 scale = 6;
             }
@@ -75,7 +78,7 @@ public class JdbcTrinoClient extends JdbcClient {
 
         if (trinoType.startsWith("array")) {
             String trinoArrType = trinoType.substring(6, trinoType.length() - 
1);
-            fieldSchema.setDataTypeName(trinoArrType);
+            fieldSchema.setDataTypeName(Optional.of(trinoArrType));
             Type type = jdbcTypeToDoris(fieldSchema);
             return ArrayType.create(type, true);
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchema.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchema.java
new file mode 100644
index 00000000000..735de93e9eb
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchema.java
@@ -0,0 +1,91 @@
+// 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.doris.datasource.jdbc.util;
+
+import lombok.Data;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Optional;
+
+@Data
+public class JdbcFieldSchema {
+    protected String columnName;
+    // The SQL type of the corresponding java.sql.types (Type ID)
+    protected int dataType;
+    // The SQL type of the corresponding java.sql.types (Type Name)
+    protected Optional<String> dataTypeName;
+    // For CHAR/DATA, columnSize means the maximum number of chars.
+    // For NUMERIC/DECIMAL, columnSize means precision.
+    protected Optional<Integer> columnSize;
+    protected Optional<Integer> decimalDigits;
+    // Base number (usually 10 or 2)
+    protected int numPrecRadix;
+    // column description
+    protected String remarks;
+    // This length is the maximum number of bytes for CHAR type
+    // for utf8 encoding, if columnSize=10, then charOctetLength=30
+    // because for utf8 encoding, a Chinese character takes up 3 bytes
+    protected int charOctetLength;
+    protected boolean isAllowNull;
+
+    public JdbcFieldSchema(ResultSet rs) throws SQLException {
+        this.columnName = rs.getString("COLUMN_NAME");
+        this.dataType = getInteger(rs, "DATA_TYPE").orElseThrow(() -> new 
IllegalStateException("DATA_TYPE is null"));
+        this.dataTypeName = Optional.ofNullable(rs.getString("TYPE_NAME"));
+        this.columnSize = getInteger(rs, "COLUMN_SIZE");
+        this.decimalDigits =  getInteger(rs, "DECIMAL_DIGITS");
+        this.numPrecRadix = rs.getInt("NUM_PREC_RADIX");
+        this.isAllowNull = rs.getInt("NULLABLE") != 
DatabaseMetaData.columnNoNulls;
+        this.remarks = rs.getString("REMARKS");
+        this.charOctetLength = rs.getInt("CHAR_OCTET_LENGTH");
+    }
+
+    public JdbcFieldSchema(ResultSet rs, Map<String, String> 
dataTypeOverrides) throws SQLException {
+        this.columnName = rs.getString("COLUMN_NAME");
+        this.dataType = getInteger(rs, "DATA_TYPE").orElseThrow(() -> new 
IllegalStateException("DATA_TYPE is null"));
+        this.dataTypeName = 
Optional.ofNullable(dataTypeOverrides.getOrDefault(columnName, 
rs.getString("TYPE_NAME")));
+        this.columnSize = getInteger(rs, "COLUMN_SIZE");
+        this.decimalDigits =  getInteger(rs, "DECIMAL_DIGITS");
+        this.numPrecRadix = rs.getInt("NUM_PREC_RADIX");
+        this.isAllowNull = rs.getInt("NULLABLE") != 0;
+        this.remarks = rs.getString("REMARKS");
+        this.charOctetLength = rs.getInt("CHAR_OCTET_LENGTH");
+    }
+
+    public JdbcFieldSchema(ResultSetMetaData metaData, int columnIndex) throws 
SQLException {
+        this.columnName = metaData.getColumnName(columnIndex);
+        this.dataType = metaData.getColumnType(columnIndex);
+        this.dataTypeName = 
Optional.ofNullable(metaData.getColumnTypeName(columnIndex));
+        this.columnSize = Optional.of(metaData.getPrecision(columnIndex));
+        this.decimalDigits = Optional.of(metaData.getScale(columnIndex));
+    }
+
+    protected static Optional<Integer> getInteger(ResultSet resultSet, String 
columnLabel)
+            throws SQLException {
+        int value = resultSet.getInt(columnLabel);
+        if (resultSet.wasNull()) {
+            return Optional.empty();
+        }
+        return Optional.of(value);
+    }
+}
+


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to