nzw921rx opened a new pull request, #11165:
URL: https://github.com/apache/seatunnel/pull/11165

   ## Purpose of this pull request
   
   Related #11127
   
   PR #11127 added `optionRule()` validation in 
`FactoryUtil.createOptionalCatalog()`, closing the last unvalidated factory 
path. However, the JDBC `BASE_CATALOG_RULE` declares `username` and `password` 
as **required**, while the runtime code treats them as optional — causing a 
regression for passwordless / Kerberos / OS-authenticated JDBC connections.
   
   This PR relaxes `baseCatalogRule()` to declare `USERNAME` and `PASSWORD` as 
**optional**, aligning the catalog validation rule with the actual runtime 
behavior.
   
   ## CatalogFactory Validation Impact Analysis
   
   The following table shows all CatalogFactory implementations affected by 
`createOptionalCatalog` validation (the only path that enforces `optionRule()`):
   
   ### A. Affected by `createOptionalCatalog` validation (走 
`createOptionalCatalog` 路径)
   
   | Factory | Before #11127 (no validation) | After #11127 (validation 
enforced) | Impact | Fix in this PR |
   
|---------|-------------------------------|-------------------------------------|--------|----------------|
   | MySqlCatalogFactory | No validation | `required(URL, USERNAME, PASSWORD)` 
| Passwordless config rejected | USERNAME/PASSWORD → optional |
   | PostgresCatalogFactory | No validation | `required(URL, USERNAME, 
PASSWORD)` | Same as above | Same fix |
   | OracleCatalogFactory | No validation | `required(URL, USERNAME, PASSWORD)` 
| Same as above | Same fix |
   | SqlServerCatalogFactory | No validation | `required(URL, USERNAME, 
PASSWORD)` | Same as above | Same fix |
   | OceanBaseCatalogFactory | No validation | `required(URL, USERNAME, 
PASSWORD, COMPATIBLE_MODE)` | Same as above | Same fix (COMPATIBLE_MODE stays 
required) |
   | RedshiftCatalogFactory | No validation | `required(URL, USERNAME, 
PASSWORD)` | Same as above | Same fix |
   | TiDBCatalogFactory | No validation | `required(URL, USERNAME, PASSWORD)` | 
Same as above | Same fix |
   | DamengCatalogFactory | No validation | `required(URL, USERNAME, PASSWORD)` 
| Same as above | Same fix |
   | XuguCatalogFactory | No validation | `required(URL, USERNAME, PASSWORD)` | 
Same as above | Same fix |
   | KingbaseCatalogFactory | No validation | `required(URL, USERNAME, 
PASSWORD)` | Same as above | Same fix |
   | SapHanaCatalogFactory | No validation | `required(URL, USERNAME, 
PASSWORD)` | Same as above | Same fix |
   | HighGoCatalogFactory | No validation | `required(URL, USERNAME, PASSWORD)` 
| Same as above | Same fix |
   | IrisCatalogFactory | No validation | `required(URL, USERNAME, PASSWORD)` | 
Same as above | Same fix |
   | OpenGaussCatalogFactory | No validation | `required(URL, USERNAME, 
PASSWORD)` | Same as above | Same fix |
   | DuckDBCatalogFactory | No validation | `required(URL)` only | No impact 
(already fixed in #11127) | N/A |
   | KuduCatalogFactory | No validation | `required(MASTER)` + conditional 
Kerberos | No impact (config always has `master`) | N/A |
   
   ### B. NOT affected — bypass `createOptionalCatalog` entirely (不走 
`createOptionalCatalog` 路径)
   
   These factories use `new XxxCatalogFactory().createCatalog()` or 
`discoverFactory` + `createCatalog` directly, **never triggering `optionRule()` 
validation**. Listed for completeness.
   
   | Factory | `optionRule()` | Catalog creation path | Impact |
   |---------|---------------|----------------------|--------|
   | PaimonCatalogFactory | `required(WAREHOUSE, DATABASE, TABLE)` + 
optional(...) | `PaimonSourceFactory` → `new 
PaimonCatalogFactory().createCatalog()`; Sink → `discoverFactory` | No impact 
(validation not triggered) |
   | IcebergCatalogFactory | `required(CATALOG_NAME, NAMESPACE, TABLE, 
CATALOG_PROPS)` + optional(...) | `IcebergSourceFactory` → `new 
IcebergCatalogFactory().createCatalog()`; Sink → `discoverFactory` | No impact |
   | DorisCatalogFactory | `required(FENODES, QUERY_PORT, USERNAME, PASSWORD)` 
| `DorisSourceFactory` → `new DorisCatalogFactory().createCatalog()`; Sink → 
`discoverFactory` | No impact |
   | StarRocksCatalogFactory | `required(BASE_URL, USERNAME, PASSWORD)` | Sink 
→ `discoverFactory` + `createCatalog` | No impact |
   | ClickhouseCatalogFactory | `required(HOST, DATABASE, USERNAME, PASSWORD)` 
| Sink → `new ClickhouseCatalog(config, ...)` (bypasses factory entirely) | No 
impact |
   | MongodbCatalogFactory | `required(URI, DATABASE)` | Source/Sink internal 
instantiation | No impact |
   | DatabendCatalogFactory | `required(URL, DATABASE, USERNAME, PASSWORD)` | 
Source/Sink internal instantiation | No impact |
   | MaxComputeCatalogFactory | `required(ENDPOINT, PROJECT, TABLE_NAME)` + 
optional(ACCESS_ID, ACCESS_KEY, ...) | Sink SaveMode internal | No impact |
   | TypesenseCatalogFactory | `required(HOSTS, PROTOCOL, APIKEY)` | Sink → 
`discoverFactory` | No impact |
   | HudiCatalogFactory | `required(TABLE_DFS_PATH)` + 
optional(CONF_FILES_PATH) | Sink → `discoverFactory` | No impact |
   | MilvusCatalogFactory | Empty rule (`OptionRule.builder().build()`) | Sink 
→ `discoverFactory` | No impact |
   | ElasticSearchCatalogFactory | Empty rule | Sink → `discoverFactory` | No 
impact |
   | EasysearchCatalogFactory | Empty rule | Sink → `discoverFactory` | No 
impact |
   | HbaseCatalogFactory | Empty rule | Sink SaveMode internal | No impact |
   | LocalFileCatalogFactory | Empty rule | Sink SaveMode internal | No impact |
   | HdfsFileCatalogFactory | Empty rule | Sink SaveMode internal | No impact |
   | S3FileCatalogFactory | Empty rule | Sink SaveMode internal | No impact |
   | OssFileCatalogFactory | Empty rule | Sink SaveMode internal | No impact |
   | FtpFileCatalogFactory | Empty rule | Sink SaveMode internal | No impact |
   | SftpFileCatalogFactory | Empty rule | Sink SaveMode internal | No impact |
   | LanceCatalogFactory | Empty rule (was `null`, fixed in #11127) | No 
`@AutoService` — SPI unreachable | No impact |
   
   ## Why USERNAME/PASSWORD should be optional
   
   | Layer | USERNAME | PASSWORD |
   |-------|----------|----------|
   | `JdbcConnectionConfig.of()` | `getOptional()` — nullable | `getOptional()` 
— nullable |
   | `extractCatalogConfig()` | Only put into map when present | Only put into 
map when present |
   | `AbstractJdbcCatalog` constructor | `checkArgument(isNotBlank)` at runtime 
| No validation — can be null |
   | `getConnectionProperties()` | Skipped if null | Skipped if null |
   
   Legitimate use cases for missing credentials:
   - Passwordless local development databases
   - Kerberos / GSSAPI authentication
   - OS-level authentication (peer auth in PostgreSQL)
   - Embedded databases (DuckDB — already fixed in #11127)
   
   ## Changes
   
   1. `JdbcCommonOptions.baseCatalogRule()`: Move `USERNAME` and `PASSWORD` 
from `required` to `optional`
   2. `JdbcCatalogFactoryTest`: Add 6 test cases covering no-credential and 
partial-credential scenarios
   3. `docs/en/introduction/concepts/incompatible-changes.md`: Document the 
`createOptionalCatalog` validation addition and DuckDB rule change
   4. `docs/zh/introduction/concepts/incompatible-changes.md`: Same in Chinese
   
   ## Does this PR introduce _any_ user-facing change?
   
   Yes — this is a **compatibility fix** that prevents a regression introduced 
by #11127. Without this change, JDBC jobs using passwordless connections would 
fail at startup with `OptionValidationException`. After this fix, the behavior 
matches the pre-#11127 state (credentials are optional).
   
   ## How was this patch tested?
   
   Unit tests in `JdbcCatalogFactoryTest`:
   
   - `testCatalogConfigWithUrlOnly` — URL-only config (no credentials) passes 
validation
   - `testCatalogConfigWithUsernameOnly` — URL + username (no password) passes 
validation
   - `testCatalogConfigMimicsExtractCatalogConfig` — config matching 
`extractCatalogConfig()` output passes
   - `testPostgresCatalogConfigWithoutPassword` — PostgreSQL without password 
passes
   - `testOceanBaseCatalogConfigWithoutPassword` — OceanBase with 
compatible_mode but no password passes
   - `testDuckDBCatalogConfigNoCredentials` — DuckDB URL-only passes
   
   ```bash
   ./mvnw spotless:apply -pl seatunnel-connectors-v2/connector-jdbc
   ./mvnw test -pl seatunnel-connectors-v2/connector-jdbc 
-Dtest=JdbcCatalogFactoryTest
   ```
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to