Repository: apache/shardingsphere (2026-07-14T05:49:08Z)

Issue:
Oracle metadata loader skips identity and collation columns on Oracle 18c and later
## Bug Report

### Which version of ShardingSphere did you use?
master @ 620e40a33c3 / 5.5.4-SNAPSHOT

### Which project did you use? ShardingSphere-JDBC or ShardingSphere-Proxy?
Both (kernel-level)

### Expected behavior
On Oracle 18c and later the metadata loader should select the `IDENTITY_COLUMN` and `COLLATION` columns, mark identity columns as generated, and mark `_CS` collated columns as case sensitive.

### Actual behavior
On those versions both columns are omitted from the SELECT, identity columns load as `generated=false`, and every column loads as `caseSensitive=false`.

### Reason analyze (If you can)
`OracleMetaDataLoader.versionContainsCollation()` and `versionContainsIdentityColumn()` (metadata/data/loader/OracleMetaDataLoader.java) compare major and minor independently: `getDatabaseMajorVersion() >= 12 && getDatabaseMinorVersion() >= N`. Oracle 18c and later report `getDatabaseMinorVersion() = 0`, so the minor check is always false and the version gate never passes. A lexicographic comparison (`major > 12 || major == 12 && minor >= N`) is required, matching the major-based gating already used by `SQLServerMetaDataLoader.versionContainsHiddenColumn()`.

### Steps to reproduce the behavior, such as: SQL to execute, sharding rule configuration, when exception occur etc.
Load table metadata from an Oracle 19c database; identity and collation attributes are missing on the loaded columns.

### Example codes for reproduce this issue (such as a github link).
N/A




Discussion:

Patch:
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 487a3a7b7861a..d9ab902c04a1f 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -40,6 +40,7 @@
 1. Sharding: Compute the Snowflake key generator epoch in UTC instead of the JVM default timezone - [#38932](https://github.com/apache/shardingsphere/pull/38932)
 1. Proxy: Fix MySQL BLOB data corruption when string-like prepared statement parameters target BLOB columns - [#39072](https://github.com/apache/shardingsphere/pull/39072)
 1. Agent: Fix wrong target class name in StaticMethodAdviceExecutor error logs - [#39077](https://github.com/apache/shardingsphere/pull/39077)
+1. Metadata: Fix Oracle metadata version comparison skipping identity and collation columns on 18c and later - [#39104](https://github.com/apache/shardingsphere/pull/39104)
 
 ### Enhancements
 
diff --git a/database/connector/dialect/oracle/src/main/java/org/apache/shardingsphere/database/connector/oracle/metadata/data/loader/OracleMetaDataLoader.java b/database/connector/dialect/oracle/src/main/java/org/apache/shardingsphere/database/connector/oracle/metadata/data/loader/OracleMetaDataLoader.java
index 533a2c76819f1..744988e20b0a4 100644
--- a/database/connector/dialect/oracle/src/main/java/org/apache/shardingsphere/database/connector/oracle/metadata/data/loader/OracleMetaDataLoader.java
+++ b/database/connector/dialect/oracle/src/main/java/org/apache/shardingsphere/database/connector/oracle/metadata/data/loader/OracleMetaDataLoader.java
@@ -177,11 +177,16 @@ private String getTableMetaDataSQL(final Collection<String> tables, final Databa
     }
     
     private boolean versionContainsCollation(final DatabaseMetaData databaseMetaData) throws SQLException {
-        return databaseMetaData.getDatabaseMajorVersion() >= COLLATION_START_MAJOR_VERSION && databaseMetaData.getDatabaseMinorVersion() >= COLLATION_START_MINOR_VERSION;
+        return isVersionAtLeast(databaseMetaData, COLLATION_START_MAJOR_VERSION, COLLATION_START_MINOR_VERSION);
     }
     
     private boolean versionContainsIdentityColumn(final DatabaseMetaData databaseMetaData) throws SQLException {
-        return databaseMetaData.getDatabaseMajorVersion() >= COLLATION_START_MAJOR_VERSION && databaseMetaData.getDatabaseMinorVersion() >= IDENTITY_COLUMN_START_MINOR_VERSION;
+        return isVersionAtLeast(databaseMetaData, COLLATION_START_MAJOR_VERSION, IDENTITY_COLUMN_START_MINOR_VERSION);
+    }
+    
+    private boolean isVersionAtLeast(final DatabaseMetaData databaseMetaData, final int major, final int minor) throws SQLException {
+        int majorVersion = databaseMetaData.getDatabaseMajorVersion();
+        return majorVersion > major || majorVersion == major && databaseMetaData.getDatabaseMinorVersion() >= minor;
     }
     
     private Map<String, Collection<IndexMetaData>> loadIndexMetaData(final Connection connection, final Collection<String> tableNames, final String schema) throws SQLException {


Test patch:
diff --git a/database/connector/dialect/oracle/src/test/java/org/apache/shardingsphere/database/connector/oracle/metadata/data/loader/OracleMetaDataLoaderTest.java b/database/connector/dialect/oracle/src/test/java/org/apache/shardingsphere/database/connector/oracle/metadata/data/loader/OracleMetaDataLoaderTest.java
index 3685a15b8452f..faf6159207d0d 100644
--- a/database/connector/dialect/oracle/src/test/java/org/apache/shardingsphere/database/connector/oracle/metadata/data/loader/OracleMetaDataLoaderTest.java
+++ b/database/connector/dialect/oracle/src/test/java/org/apache/shardingsphere/database/connector/oracle/metadata/data/loader/OracleMetaDataLoaderTest.java
@@ -221,18 +221,18 @@ private ResultSet mockPrimaryKeysMetaDataResultSet() throws SQLException {
     }
     
     private String getTableMetaDataSQL(final int majorVersion, final int minorVersion) {
-        if (majorVersion >= 12 && minorVersion >= 2) {
+        if (majorVersion > 12 || majorVersion == 12 && minorVersion >= 2) {
             return ALL_TAB_COLUMNS_SQL_WITH_IDENTITY_AND_COLLATION;
         }
-        if (majorVersion >= 12 && minorVersion == 1) {
+        if (majorVersion == 12 && minorVersion == 1) {
             return ALL_TAB_COLUMNS_SQL_WITH_IDENTITY;
         }
         return ALL_TAB_COLUMNS_SQL_WITHOUT_IDENTITY_AND_COLLATION;
     }
     
     private ColumnMetaData getExpectedFirstColumnMetaData(final int majorVersion, final int minorVersion, final boolean withPrimaryKey) {
-        boolean generated = majorVersion >= 12 && minorVersion >= 1;
-        boolean caseSensitive = majorVersion >= 12 && minorVersion >= 2;
+        boolean generated = majorVersion > 12 || majorVersion == 12 && minorVersion >= 1;
+        boolean caseSensitive = majorVersion > 12 || majorVersion == 12 && minorVersion >= 2;
         return new ColumnMetaData("id", Types.NUMERIC, withPrimaryKey, generated, caseSensitive, true, false, false);
     }
     
@@ -276,6 +276,7 @@ private static Stream<Arguments> assertLoadArguments() {
                 Arguments.of("major12Minor2WithPrimaryKey", 12, 2, true, false),
                 Arguments.of("major12Minor1WithPrimaryKey", 12, 1, true, false),
                 Arguments.of("major11Minor2WithPrimaryKey", 11, 2, true, false),
+                Arguments.of("major19Minor0WithPrimaryKey", 19, 0, true, false),
                 Arguments.of("major12Minor2WithPrimaryKeyAndNullCollation", 12, 2, true, true));
     }
 }