diff --git a/fe/be-java-extensions/jdbc-scanner/pom.xml b/fe/be-java-extensions/jdbc-scanner/pom.xml index bebf1c4ffc48ba..54da3601cc4ba0 100644 --- a/fe/be-java-extensions/jdbc-scanner/pom.xml +++ b/fe/be-java-extensions/jdbc-scanner/pom.xml @@ -45,6 +45,10 @@ under the License. HikariCP provided + + org.semver4j + semver4j + diff --git a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java index 4336d09e744b65..08f5e65181e4dd 100644 --- a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java +++ b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java @@ -32,11 +32,13 @@ import org.apache.thrift.TDeserializer; import org.apache.thrift.TException; import org.apache.thrift.protocol.TBinaryProtocol; +import org.semver4j.Semver; import java.io.FileNotFoundException; import java.lang.reflect.Array; import java.net.MalformedURLException; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -65,6 +67,7 @@ public abstract class BaseJdbcExecutor implements JdbcExecutor { protected VectorTable outputTable = null; protected int batchSizeNum = 0; protected int curBlockRows = 0; + protected String jdbcDriverVersion; public BaseJdbcExecutor(byte[] thriftParams) throws Exception { TJdbcExecutorCtorParams request = new TJdbcExecutorCtorParams(); @@ -91,11 +94,12 @@ public BaseJdbcExecutor(byte[] thriftParams) throws Exception { .setConnectionPoolKeepAlive(request.connection_pool_keep_alive); JdbcDataSource.getDataSource().setCleanupInterval(request.connection_pool_cache_clear_time); init(config, request.statement); + this.jdbcDriverVersion = getJdbcDriverVersion(); } public void close() throws Exception { try { - if (stmt != null) { + if (stmt != null && !stmt.isClosed()) { try { stmt.cancel(); } catch (SQLException e) { @@ -524,6 +528,30 @@ private void insertNullColumn(int parameterIndex, ColumnType.Type dorisType) } } + private String getJdbcDriverVersion() { + try { + if (conn != null) { + DatabaseMetaData metaData = conn.getMetaData(); + return metaData.getDriverVersion(); + } else { + return null; + } + } catch (SQLException e) { + LOG.warn("Failed to retrieve JDBC Driver version", e); + return null; + } + } + + protected boolean isJdbcVersionGreaterThanOrEqualTo(String version) { + Semver currentVersion = Semver.coerce(jdbcDriverVersion); + Semver targetVersion = Semver.coerce(version); + if (currentVersion != null && targetVersion != null) { + return currentVersion.isGreaterThanOrEqualTo(targetVersion); + } else { + return false; + } + } + protected String trimSpaces(String str) { int end = str.length() - 1; while (end >= 0 && str.charAt(end) == ' ') { diff --git a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/OracleJdbcExecutor.java b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/OracleJdbcExecutor.java index 662f324eb23de7..6f38895335b986 100644 --- a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/OracleJdbcExecutor.java +++ b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/OracleJdbcExecutor.java @@ -33,7 +33,7 @@ import java.nio.charset.StandardCharsets; import java.sql.Clob; import java.sql.SQLException; -import java.time.LocalDate; +import java.sql.Timestamp; import java.time.LocalDateTime; public class OracleJdbcExecutor extends BaseJdbcExecutor { @@ -65,42 +65,83 @@ protected void initializeBlock(int columnCount, String[] replaceStringList, int @Override protected Object getColumnValue(int columnIndex, ColumnType type, String[] replaceStringList) throws SQLException { - try { - switch (type.getType()) { - case TINYINT: - return resultSet.getObject(columnIndex + 1, Byte.class); - case SMALLINT: - return resultSet.getObject(columnIndex + 1, Short.class); - case INT: - return resultSet.getObject(columnIndex + 1, Integer.class); - case BIGINT: - return resultSet.getObject(columnIndex + 1, Long.class); - case FLOAT: - return resultSet.getObject(columnIndex + 1, Float.class); - case DOUBLE: - return resultSet.getObject(columnIndex + 1, Double.class); - case LARGEINT: - case DECIMALV2: - case DECIMAL32: - case DECIMAL64: - case DECIMAL128: - return resultSet.getObject(columnIndex + 1, BigDecimal.class); - case DATE: - case DATEV2: - return resultSet.getObject(columnIndex + 1, LocalDate.class); - case DATETIME: - case DATETIMEV2: - return resultSet.getObject(columnIndex + 1, LocalDateTime.class); - case CHAR: - case VARCHAR: - case STRING: - return resultSet.getObject(columnIndex + 1); - default: - throw new IllegalArgumentException("Unsupported column type: " + type.getType()); - } - } catch (AbstractMethodError e) { - LOG.warn("Detected an outdated ojdbc driver. Please use ojdbc8 or above.", e); - throw new SQLException("Detected an outdated ojdbc driver. Please use ojdbc8 or above."); + if (isJdbcVersionGreaterThanOrEqualTo("12.2.0")) { + return newGetColumnValue(columnIndex, type, replaceStringList); + } else { + return oldGetColumnValue(columnIndex, type, replaceStringList); + } + } + + private Object newGetColumnValue(int columnIndex, ColumnType type, String[] replaceStringList) throws SQLException { + switch (type.getType()) { + case TINYINT: + return resultSet.getObject(columnIndex + 1, Byte.class); + case SMALLINT: + return resultSet.getObject(columnIndex + 1, Short.class); + case INT: + return resultSet.getObject(columnIndex + 1, Integer.class); + case BIGINT: + return resultSet.getObject(columnIndex + 1, Long.class); + case FLOAT: + return resultSet.getObject(columnIndex + 1, Float.class); + case DOUBLE: + return resultSet.getObject(columnIndex + 1, Double.class); + case LARGEINT: + case DECIMALV2: + case DECIMAL32: + case DECIMAL64: + case DECIMAL128: + return resultSet.getObject(columnIndex + 1, BigDecimal.class); + case DATETIME: + case DATETIMEV2: + return resultSet.getObject(columnIndex + 1, LocalDateTime.class); + case CHAR: + case VARCHAR: + case STRING: + return resultSet.getObject(columnIndex + 1); + default: + throw new IllegalArgumentException("Unsupported column type: " + type.getType()); + } + } + + private Object oldGetColumnValue(int columnIndex, ColumnType type, String[] replaceStringList) throws SQLException { + switch (type.getType()) { + case TINYINT: + byte tinyIntVal = resultSet.getByte(columnIndex + 1); + return resultSet.wasNull() ? null : tinyIntVal; + case SMALLINT: + short smallIntVal = resultSet.getShort(columnIndex + 1); + return resultSet.wasNull() ? null : smallIntVal; + case INT: + int intVal = resultSet.getInt(columnIndex + 1); + return resultSet.wasNull() ? null : intVal; + case BIGINT: + long bigIntVal = resultSet.getLong(columnIndex + 1); + return resultSet.wasNull() ? null : bigIntVal; + case FLOAT: + float floatVal = resultSet.getFloat(columnIndex + 1); + return resultSet.wasNull() ? null : floatVal; + case DOUBLE: + double doubleVal = resultSet.getDouble(columnIndex + 1); + return resultSet.wasNull() ? null : doubleVal; + case LARGEINT: + case DECIMALV2: + case DECIMAL32: + case DECIMAL64: + case DECIMAL128: + BigDecimal decimalVal = resultSet.getBigDecimal(columnIndex + 1); + return resultSet.wasNull() ? null : decimalVal; + case DATETIME: + case DATETIMEV2: + Timestamp timestampVal = resultSet.getTimestamp(columnIndex + 1); + return resultSet.wasNull() ? null : timestampVal.toLocalDateTime(); + case CHAR: + case VARCHAR: + case STRING: + Object stringVal = resultSet.getObject(columnIndex + 1); + return resultSet.wasNull() ? null : stringVal; + default: + throw new IllegalArgumentException("Unsupported column type: " + type.getType()); } } diff --git a/fe/pom.xml b/fe/pom.xml index af4a3f34c53564..5cb0627d3fcb17 100644 --- a/fe/pom.xml +++ b/fe/pom.xml @@ -360,6 +360,7 @@ under the License. 1.12.0 0.8.10 202 + 5.3.0 @@ -1671,6 +1672,11 @@ under the License. concurrent ${airlift.version} + + org.semver4j + semver4j + ${semver4j.version} + diff --git a/regression-test/data/external_table_p0/jdbc/test_oracle_jdbc_catalog.out b/regression-test/data/external_table_p0/jdbc/test_oracle_jdbc_catalog.out index 9fea31242a29b9..82afecb61bd2b3 100644 --- a/regression-test/data/external_table_p0/jdbc/test_oracle_jdbc_catalog.out +++ b/regression-test/data/external_table_p0/jdbc/test_oracle_jdbc_catalog.out @@ -265,3 +265,7 @@ Doris -- !query_lower_3 -- doris +-- !query_ojdbc6_all_types -- +1 111 123 7456123.89 573 34 673.43 34.1264 60.0 23.231 99 9999 999999999 999999999999999999 999 99999 9999999999 9999999999999999999 1 china beijing alice abcdefghrjkmnopq 123.45 12300 0.0012345 2022-01-21T05:23:01 2019-11-12T20:33:57.999 2019-11-12T20:33:57.999998 2019-11-12T20:33:57.999996 2019-11-12T20:33:57.999997 223-9 12 10:23:1.123457000 +2 \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N + diff --git a/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy b/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy index 057723a808e04d..571dda0e5d8085 100644 --- a/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy +++ b/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy @@ -21,6 +21,7 @@ suite("test_oracle_jdbc_catalog", "p0,external,oracle,external_docker,external_d String s3_endpoint = getS3Endpoint() String bucket = getS3BucketName() String driver_url = "https://${bucket}.${s3_endpoint}/regression/jdbc_driver/ojdbc8.jar" + String driver6_url = "https://${bucket}.${s3_endpoint}/regression/jdbc_driver/ojdbc6.jar" if (enabled != null && enabled.equalsIgnoreCase("true")) { String catalog_name = "oracle_catalog"; String internal_db_name = "regression_test_jdbc_catalog_p0"; @@ -281,5 +282,20 @@ suite("test_oracle_jdbc_catalog", "p0,external,oracle,external_docker,external_d qt_query_lower_3 """ select doris_3 from doris_test.lower_test; """ sql """drop catalog if exists ${catalog_name} """ + + // test for ojdbc6 + sql """drop catalog if exists oracle_ojdbc6; """ + sql """create catalog if not exists oracle_ojdbc6 properties( + "type"="jdbc", + "user"="doris_test", + "password"="123456", + "jdbc_url" = "jdbc:oracle:thin:@${externalEnvIp}:${oracle_port}:${SID}", + "driver_url" = "${driver6_url}", + "driver_class" = "oracle.jdbc.OracleDriver" + );""" + sql """ use oracle_ojdbc6.DORIS_TEST; """ + qt_query_ojdbc6_all_types """ select * from oracle_ojdbc6.DORIS_TEST.TEST_ALL_TYPES order by 1; """ + + sql """drop catalog if exists oracle_ojdbc6; """ } }