Repository navigation
Description
Search before asking
- I had searched in the issues and found no similar issues.
- I searched the open and closed pull requests for the affected classes and for locale dependent type mapping.
What happened
The JDBC dialect type converters match the source column type against the dialect type constants with String.toUpperCase() / String.toLowerCase() without Locale.ROOT. The result therefore depends on the JVM default locale.
In a Turkish or Azerbaijani locale "i" is upper-cased to "İ" (U+0130), so a type name such as INTEGER becomes İNTEGER and no longer matches the constant. The converter then falls through to its default branch and the job fails with an unsupported type error instead of mapping the column.
The following converters are affected in dev:
| Dialect | Converter | Type name that breaks |
|---|---|---|
| DB2 | DB2TypeConverter |
INTEGER, BIGINT, SMALLINT, BINARY |
| DaMeng | DmdbTypeConverter |
INT, INTEGER, BIGINT, SMALLINT |
| IRIS | IrisTypeConverter |
INT, INTEGER, BIGINT, SERIAL |
| Kingbase | KingbaseTypeConverter |
INT, INTEGER, BIGINT |
| Oracle | OracleTypeConverter |
INTEGER, INTERVAL, BINARY_FLOAT |
| PostgreSQL | PostgresTypeConverter |
INT4, INT8, BIGSERIAL |
| Redshift | RedshiftTypeConverter |
INT, BIGINT, SMALLINT |
| SAP HANA | SapHanaTypeConverter |
INT, INTEGER, BIGINT |
| Xugu | XuguTypeConverter |
INT, INTEGER, BIGINT, TINYINT |
| YashanDB | YashanDbTypeConverter |
INT, INTEGER, BIGINT, SMALLINT |
PostgresTypeConverter lower-cases the type name, so it only breaks when the type name contains an upper-case I (INT4 -> ınt4).
The MySQL, OceanBase and SQL Server converters are already covered by #13076 and #13077, and JdbcDialect / CatalogUtils by #13063, so they are not part of this report.
What you expected to happen
A JDBC dialect type converter maps the same source type to the same SeaTunnel type on every worker, regardless of the JVM default locale of that worker.
SeaTunnel Version
dev
SeaTunnel Config
Not configuration dependent; the reproduction uses the affected type converters directly.
Running Command
./mvnw -pl seatunnel-connectors-v2/connector-jdbc \
-Dtest='Db2TypeConverterTest,DmdbTypeConverterTest,IrisTypeConverterTest,\
KingbaseTypeConverterTest,OracleTypeConverterTest,PostgresTypeConverterTest,\
RedshiftTypeConverterTest,SapHanaTypeConverterTest,XuguTypeConverterTest,\
YashanDbTypeConverterTest' testError Exception
java.lang.RuntimeException: Unsupported type INT
at org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.db2.DB2TypeConverter.convert(DB2TypeConverter.java:...)
Zeta or Flink or Spark Version
Not engine specific. The failure is in the JDBC connector.
Java or Scala Version
Not version specific. Reproduced on JDK 17 with -Duser.language=tr -Duser.country=TR.
Are you willing to submit PR?
- Yes I am willing to submit a PR!
Code of Conduct
- I agree to follow this project's Code of Conduct.
Activity
SEZ9 commentedon Nov 1, 2026
Thanks for the detailed report. This looks like a valid follow-up to #13063, #13076 and #13077, and the table of affected converters makes the scope clear.
Since you're willing to submit a PR, one PR covering all ten converters is fine. In that PR, please pass
Locale.ROOTto thetoUpperCase()/toLowerCase()calls and add a test that exercises the converters under a Turkish locale (as in your reproduction with-Duser.language=tr -Duser.country=TR) so this does not regress. A quick scan of the rest ofconnector-jdbcfor any remaining locale-dependent case conversions would also be welcome.sharpca commentedon Nov 1, 2026
Thanks @SEZ9. I opened #13083, which passes
Locale.ROOTto all ten converters listed in the report and addsJdbcTypeConverterLocaleTest, which runs those converters undertr-TRwith lower-case type names (integer/int, and upper-caseINT4for PostgreSQL) and asserts the resulting SeaTunnel type. The test fails against the unpatchedDB2TypeConverterwithUnsupported type integer, so it guards the regression.[Fix][Connector-V2] Cover the remaining locale dependent case convers…
sharpca commentedon Nov 1, 2026
Thanks for the guidance. #13083 now covers all ten converters plus the scan you asked for.
Locale.ROOTin the ten converters — everytoUpperCase()/toLowerCase()in the converters listed in the report now passesLocale.ROOT(34 call sites in the PR).Turkish locale test —
JdbcTypeConverterLocaleTestsetsnew Locale("tr", "TR"), converts a type name through each affected converter, and restores the previous default in@AfterEach, so the locale cannot leak into other tests sharing the JVM. It coversINTEGER,BIGINT,INT4and the other names from the table.Result of the scan of the rest of
connector-jdbc— three more places lower-cased with the default locale:MysqlDialect,OceanBaseMysqlDialect,OracleDialect,RedshiftDialect,SqlServerDialect,YashanDbDialectgetQuery().toLowerCase()in the row countWHEREcheckCollationBasedSplitters.toLowerCase()in the case insensitive collation normalisationJdbcSourceFactoryvalue.toLowerCase().startsWith("where")in thewhere_conditionprefix validatorThese are fixed in the same PR. The six dialects now follow the pattern
PostgresDialectalready used here.CollationBasedSplitteris included because the locale changes the comparison result there, not only the spelling of a constant.JdbcDialect/CatalogUtilsare left to #13063 and the MySQL / OceanBase / SQL Server converters to #13076 and #13077, as noted in the report, so the PRs stay disjoint.Verification (JDK 17,
./mvnw -pl seatunnel-connectors-v2/connector-jdbc):JdbcTypeConverterLocaleTest— 1 test, 0 failuresMysqlDialectTest,OracleDialectTest,SqlServerDialectTest,YashanDbDialectTest,JdbcSourceFactoryTest— 46 tests, 0 failuresspotless:check— passedThe PR workflows are still waiting for approval (
action_required), so none of this has run in CI yet.SEZ9 commentedon Nov 2, 2026
Thanks @sharpca for opening the PR rather than just confirming the analysis.
Passing
Locale.ROOTto everytoUpperCase()/toLowerCase()in the ten converters from the report is exactly the fix I was after, andJdbcTypeConverterLocaleTestrunning undertr-TRwith lower-caseinteger/intplus upper-caseINT4for PostgreSQL is the right shape of guard. That it fails against the unpatchedDB2TypeConverterwithUnsupported type integeris good evidence the test actually bites.Two small asks on the test:
tr-TRand restored even if the converter call throws. You describe it as restored, so this is likely already fine; a leakedtr-TRdefault would make unrelated tests in the same JVM fail in confusing ways.On the scan results: the six
getQuery().toLowerCase()dialect sites,CollationBasedSplitter, and theJdbcSourceFactorywhere_conditioncheck are the same class of bug, so bundling them with the converter fix is fine with me, and keepingJdbcDialect/CatalogUtilsand the MySQL / OceanBase / SQL Server converters in their separate PRs as you describe is the right call.Once the PR workflows have run, ping me here and I'll do the full review.
sharpca commentedon Nov 2, 2026
Both asks are addressed in
cabfb80d.1. One case per converter.
JdbcTypeConverterLocaleTestis now a@ParameterizedTestover a@MethodSourceof(converter, source type, expected type)pairs — ten invocations, one per dialect, with the naming pattern"{0} maps {2}". The dialect name is also carried into the assertion message, so a regression readsDB2TypeConverter folded integer to the wrong type under tr-TRinstead of an invocation index.2. Locale capture and restore. The capture moved into
@BeforeEach: the base,DISPLAYandFORMATdefaults are read first, and only then is the default switched totr-TR. The restore moved into@AfterEach, which JUnit runs even when the test body throws — so the guarantee is structural now rather than afinallyinside one combined test method.@ResourceLock("java.util.Locale")is retained in case parallel execution is enabled later.Local evidence on JDK 17 (
-pl seatunnel-connectors-v2/connector-jdbc, current head): the targeted set is 68 tests, 0 failures, 1 skipped (the container-backed Oracle test), with the locale test itself reporting 10/0/0/0.spotless:checkpasses.On the ping — I cannot send it yet. CI still has not executed on this head: the check-runs count is 0 and the workflow run for this PR stays
action_required, which means it is waiting for a maintainer to approve the run. A fork contributor cannot trigger that gate. I will post the CI results here the moment it executes.To be explicit about what is and is not established: everything above, like the earlier numbers, is local execution by me, not CI. The integration case added in
704af8840has not been compiled or run at all here (no Docker, and the e2e module's SNAPSHOT prerequisites are absent from this machine), so it depends entirely on that CI run.DanielLeens commentedon Nov 3, 2026
Hi @sharpca, thanks for addressing both test points so quickly.
On the CI status:
action_requiredhere does not mean the run is waiting for a maintainer approval. For apache/seatunnel the build for a PR runs in the contributor's fork, and theBuildcheck on the PR only reports the result of that fork run. The check on #13083 currently reports "Workflow run detection failed", and your forksharpca/seatunnelhas no workflow runs at all, so there is nothing for the check to pick up yet. There is no approval gate a maintainer can clear for this. The onlyaction_requiredrun on the apache side isLabel-when-reviewed, a review-labeling workflow that does not build or test anything.To get CI running:
Buildcheck picks the fork run up automatically within about 15 minutes.The same steps apply to #13081.
One small request for the review: the PR now touches more files than the thread lists (for example
Gbase8aTypeMapper,HiveTypeMapper,PrestoTypeMapper,PhoenixTypeConverter,SnowflakeTypeConverter, the DuckDB/Redshift/Xugu/YashanDB catalogs,DamengDataTypeConvertor,OceanBaseOracleCreateTableSqlBuilder, and the newJdbcMysqlSplitITcase). Please list all of them in the PR description with the call site and the reason each one is locale sensitive, so the review can be checked against the full scope. TheJdbcDialect/CatalogUtilsand MySQL / OceanBase / SQL Server boundaries with #13063, #13076 and #13077 look clean on the main sources.Once the fork build has run, further review continues on #13083 itself.
SEZ9 commentedon Nov 4, 2026
Thanks @sharpca —
cabfb80daddresses both test points: one parameterized invocation per converter with the dialect name carried into the assertion message, and the locale capture/restore moved into the before/after hooks so the restore is structural.Two things remain before review continues on #13083 itself:
CI has not run on the fork yet. As described above,
action_requiredon the apache side is only theLabel-when-reviewedworkflow, which does not build or test anything, and theBuildcheck on [Fix][Connector-V2] Make JDBC dialect type converters locale independent #13083 cannot pick anything up until a workflow run exists insharpca/seatunnel. There is no maintainer approval gate to clear. Please enable Actions in your fork and run the Build workflow against the PR branch (or push an empty commit); the PR check should pick it up within about 15 minutes. The same applies to [Fix][Core] Make CLI enum argument parsing locale independent #13081. This matters most for the integration case added in704af8840, which you noted has not been compiled or run locally.PR description vs. actual scope. The
Locale.ROOTchange touches more files than this thread lists (for exampleGbase8aTypeMapper,HiveTypeMapper,PrestoTypeMapper,PhoenixTypeConverter,SnowflakeTypeConverter, the DuckDB/Redshift/Xugu/YashanDB catalogs,DamengDataTypeConvertor,OceanBaseOracleCreateTableSqlBuilder, and the newJdbcMysqlSplitITcase). Please list every touched file in the PR description with the call site and why it is locale sensitive, in the same style as the table you posted above, so the review can be checked against the full set of call sites.The boundaries with #13063 (
JdbcDialect/CatalogUtils) and #13076 / #13077 (MySQL / OceanBase / SQL Server converters) look clean on the main sources — nothing needed there.Once the fork build has executed and the description is complete, I will continue on #13083.