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]
