Repository navigation
Fix jdbc-v2: report the IPv4/IPv6 Java class in getColumnClassName - #3191
polyglotAI-bot wants to merge 3 commits into
Conversation
ResultSetMetaData#getColumnClassName returned java.lang.Object for IPv4 and IPv6 columns because JdbcUtils.DATA_TYPE_CLASS_MAP mapped both types to Object. IPv4 now maps to java.net.Inet4Address and IPv6 to java.net.InetAddress: the reader returns an Inet4Address for an IPv4-mapped IPv6 value, so InetAddress is the class that getObject actually returns. getObject returns the same values as before. ArrayResultSet.convertValue used an exact class match, so an array element could not be returned for a superclass target such as InetAddress. It now uses isInstance, the same as JdbcUtils.convert. Fixes: #3189 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
IMO an IPv6 column should report java.net.Inet6Address (and not InetAddress ) . If I save an IPv4 address in a IPv6 column I'm implicitly asking for a conversion ( like 10.5.2.1 -> ::ffff:10.5.2.1 ). Like trying to save a Short value in a Long column I expect to get a Long back when I do getObject. I do not think that the DB should "remember" what type of value I passed way after the storing of it is done. Also calling ResultSet.getObject(index, java.net.Inet6Address.class) and ResultSet.getObject(index, java.net.InetAddress.class) on an IPv6 column should both work, while ResultSet.getObject(index, java.net.Inet4Address.class) should fail. For the same reason calling ResultSet.getObject(index, java.net.Inet4Address.class) and ResultSet.getObject(index, java.net.InetAddress.class) on an IPv4 column should both work, while ResultSet.getObject(index, java.net.Inet6Address.class) should fail. |
|
Thank you for the review, @ventod. I checked each of your cases on this branch with a live server (26.9). The Query:
@chernser, which option do you want?
If you select B, I will update this PR. |
…lumn-class-name # Conflicts: # docs/features.md
TriageCategory: Summary What this impacts
Concerns
Required reviewer action
|
|
Docs drift check: resolved, docs now match this PR's changes. |
Client V2 CoverageCoverage Report
Class Coverage
|
JDBC V2 CoverageCoverage Report
Class Coverage
|
JDBC V1 CoverageCoverage Report
Class Coverage
|
Client V1 CoverageCoverage Report
Class Coverage
|
docs/clickhouse-docs/jdbc.mdx listed java.net.Inet6Address as the Java class of IPv6. getColumnClassName now reports java.net.InetAddress, because an IPv4-mapped IPv6 value (::ffff:a.b.c.d) is returned as an Inet4Address. Update the Special Types row and bullet, and the V1/V2 comparison row (V1 always returns Inet6Address, so IPv6 is not fully compatible). Add the getObject(i, Inet6Address.class) migration hint. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Docs drift check: the drift is real. Fixed in 225518b (
The array section of These rows follow the current mapping in this PR (option A, |
|



Description
Fixes #3189.
ResultSetMetaData#getColumnClassNamereturnedjava.lang.ObjectforIPv4andIPv6columns. The cause isJdbcUtils.DATA_TYPE_CLASS_MAP: it mapped both types toObject.class. That map is the single source of the column class for metadata and forgetObject().IPv4now maps tojava.net.Inet4Address. The reader always returns anInet4AddressforIPv4.IPv6now maps tojava.net.InetAddress, notInet6Address.BinaryStreamReaderreadsIPv6withInetAddress.getByAddress(16 bytes), which returns anInet4Addressfor an IPv4-mapped value (::ffff:a.b.c.d). The existingJdbcDataTypeTests.testIpAddressTypesrequiresgetObject()to return thatInet4Address. JDBC definesgetColumnClassNameas the class of the instances thatgetObject()returns, soInetAddressis the correct class. WithInet6Address,JdbcUtils.convertwould convert mapped values toInet6Address, andgetObject()would return different values than before.getColumnType()staysTypes.OTHER.ResultSet#getObject()returns the same values as before.Alternative (needs a decision): to report
Inet6AddressforIPv6, as the issue expects,getObject()must return anInet6Addressfor IPv4-mapped values. That changes the behavior of an existing value path. If you want that, I can change it.Changes
JdbcUtils.getDataTypeClassMap():IPv4→Inet4Address.class,IPv6→InetAddress.class.ArrayResultSet.convertValue(): the "no conversion needed" check was an exact class match (targetType == value.getClass()).ArrayResultSet.getObject(2)uses the class from the same map, so anArray(IPv6)element failed withValue of class java.net.Inet6Address cannot be converted to class java.net.InetAddress. The check is nowtargetType.isInstance(value), the same as inJdbcUtils.convert. NoValueConverterstarget is a superclass of a value class that gets here, so no converter that ran before is skipped.docs/features.md: new "IP address type mapping" bullet.history/latest/3189.md: changelog entry.Compatibility
getColumnClassNamereports a different value forIPv4/IPv6columns. That is the fix.java.sql.Array#getArray()forArray(IPv4)/Array(IPv6)now returns anInet4Address[]/InetAddress[], not anObject[], the same as other typed arrays (for exampleUUID[]). A cast toObject[]still works.getObject(int, Class)on the result set of ajava.sql.Arraynow also accepts a superclass or interface of the element value (for exampleNumber.classfor anInt32element). Before, it threw.createArrayOf("IPv4", new String[]{...}).getResultSet().getObject(2)now throws: there is noString→Inet4Addressconverter. Before, it returned theString. A typed array ofInetAddressvalues works.Test
ResultSetMetaDataImplTest.testGetColumnClassNameOfIpAddressTypes(integration,@DataProvider):IPv4,IPv6, theirNullableandLowCardinalityforms, and an IPv4-mappedIPv6value. For each row, the test checks the type name,Types.OTHER, and the class name, and thatgetObject()returns an instance of the reported class. The IPv4-mapped row is the contrast case:getObject()still returns anInet4Address. The test runs the same checks on theVALUEcolumn ofjava.sql.Array#getResultSet(). All 5 original rows failed onmainwithexpected [...] but found [java.lang.Object].ArrayResultSetTest.testInetAddressValues(unit):getObject(2),getObject(2, InetAddress.class), and anullelement. Negative case:getObject(2, Inet4Address.class)on a non-mapped IPv6 element still throwsSQLException. Fails without theArrayResultSetchange.jdbc-v2module: 1963 unit tests pass. 775 of 777 integration tests pass. The 2 failures areConnectionTest.testSSLModeVerifyCaandConnectionTest.testSecureConnection. These SSL tests need a TLS setup that my local environment does not have. They are not related to this change. No existing tests were edited.Pre-PR validation gate
main)docs/changes_checklist.md"Conditional logic or guard changed": theArrayResultSetguard now admits superclass targets. A negative test shows that unrelated targets still throw.docs/features.mdupdated (jdbc-v2 behavior)history/latest/3189.mdStatement#executeQuery)Not in this PR
Two related defects that I found while working on this. Neither is caused by this change, and they are tracked for separate investigation:
BinaryStreamReader.readArrayItemcreates anInet6Address[]forArray(Nullable(IPv6)), so an IPv4-mapped element is likely to fail on read.InetAddressConverter.convertToIpv4comparesbytes[10] != 0xFF(abytewith anint), so it rejects every IPv4-mappedInet6Address.🤖 Generated with Claude Code
Note
Low Risk
Metadata and array typing changes are user-visible but
getObject()scalar values are unchanged; risk is mainly for code that depended onjava.lang.ObjectorObject[]for IP columns.Overview
Fixes jdbc-v2 IPv4/IPv6 metadata so
ResultSetMetaData#getColumnClassNamematches whatgetObject()actually returns (issue #3189).IPv4now reportsjava.net.Inet4Address;IPv6reportsjava.net.InetAddress(notInet6Address) because IPv4-mapped values like::ffff:10.0.0.1still come back asInet4Address. The change is inJdbcUtils’ sharedDATA_TYPE_CLASS_MAP, which drives column metadata and typed reads.ArrayResultSet.convertValuenow treats a requested type as satisfied whentargetType.isInstance(value), aligning withJdbcUtils.convertso arrayVALUEcolumns andgetObject(column, InetAddress.class)work forInet6Addresselements without bogus conversion errors.Documented behavior in
docs/features.mdanddocs/clickhouse-docs/jdbc.mdx(including V1 vs V2 IPv6 mapped-address differences).java.sql.Array#getArray()for IP arrays is now typed asInet4Address[]/InetAddress[]. Integration and unit tests cover scalar and array metadata plus array elementgetObjecttyping.Reviewed by Cursor Bugbot for commit 225518b. Bugbot is set up for automated code reviews on this repo. Configure here.