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

   ### Purpose of this pull request
   
   Fixes #10451.
   
   The MySQL catalog and the OceanBase MySQL catalog derived the `UNSIGNED` 
attribute of a column by
   searching the whole `COLUMN_TYPE` string for the word `unsigned`:
   
   ```java
   boolean unsigned = columnType.toLowerCase(Locale.ROOT).contains("unsigned");
   ```
   
   `COLUMN_TYPE` is not just the type name. For `SET` and `ENUM` columns it 
also carries the value
   list, and `mysql.event.sql_mode` is declared like this:
   
   ```
   
set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED',...,
       'ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE')
   ```
   
   So the literal value name `NO_UNSIGNED_SUBTRACTION` inside that list was 
read as the attribute. Both
   type converters then append `" UNSIGNED"` to the type name, which turns 
`SET` into the type
   `SET UNSIGNED` - a type that does not exist in MySQL:
   
   ```
   ErrorCode:[COMMON-17], ErrorDescription:['MySQL' unsupported convert type 
'SET UNSIGNED' ...]
   ```
   
   That happens during catalog discovery, so a multi-table MySQL-CDC job fails 
at startup before it
   reads a single binlog event.
   
   ### What this PR changes
   
   In MySQL the `UNSIGNED` attribute is only valid on numeric types, and it is 
always placed after an
   optional length / precision part: `int(10) unsigned`, `bigint(20) unsigned 
zerofill`, and
   `float unsigned` (no length part when declared without precision). So the 
derivation now reads the
   leading type name and checks it against the numeric types that the 
converters actually describe
   with a `*_UNSIGNED` constant:
   
   ```java
   String dataType = columnType.trim().split("[\\s(]", 
2)[0].toUpperCase(Locale.ROOT);
   return UNSIGNED_TYPE_NAMES.contains(dataType)
           && columnType.toLowerCase(Locale.ROOT).contains("unsigned");
   ```
   
   The rule lives in `JdbcCatalogUtils.isNumericUnsignedColumnType(...)` and is 
now used by both
   `MySqlCatalog.buildColumn` and `OceanBaseMySqlCatalog.buildColumn`, which 
carried the identical bug.
   Their converters are symmetric, so the `ENUM('...unsigned...')` sibling case 
failed in exactly the
   same way and is fixed by the same change.
   
   Relationship to #10453: that pull request adds defensive handling for an 
externally supplied
   `SET UNSIGNED` type name. This pull request removes the reason such a name 
is ever synthesized in
   the first place. The two are complementary and neither depends on the other.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes - it is a bug fix, and it only widens what works:
   
   - **Before**: reading a `SET` or `ENUM` column whose value list contains the 
word "unsigned"
     (through MySQL-CDC startup or through a JDBC catalog read) failed the job 
with
     `COMMON-17 unsupported convert type`.
   - **After**: the column is reported as `STRING`, which is the mapping the 
connector documentation
     already describes for `SET` and `ENUM`.
   
   Every genuinely `unsigned` numeric column is unaffected: the attribute can 
only be attached to the
   numeric types in the whitelist, and all of those are still detected, in both 
the
   `int(10) unsigned` and the `float unsigned` shape.
   
   No config option, default value, public API, SPI contract, serialization 
format or checkpoint state
   is touched. `Column#isUnsigned()` is consumed only by the two dialects' type 
converters, and only
   to decide whether to append `" UNSIGNED"`.
   
   ### How was this patch tested?
   
   Two focused unit test classes, neither of which needs a MySQL server:
   
   - `JdbcCatalogUtilsTest` covers the derivation itself: unsigned numerics in 
both shapes
     (`int(10) unsigned`, and `float unsigned` which has no length part), 
signed numerics, the exact
     `mysql.event.sql_mode` shape, the `ENUM` sibling shape, and blank input.
   - `MySqlCatalogUnsignedDetectionTest` drives the real 
`MySqlCatalog.buildColumn` with a stubbed
     `ResultSet` and asserts the resulting SeaTunnel column type for the same 
inputs, so the
     catalog-side integration is covered too. It needs no server: the catalog 
constructor probes the
     server version, and the test catalog overrides connection acquisition so 
the probe fails and the
     default version is used - which is the production fallback path when the 
probe cannot reach the
     server. `MySqlCatalogTest` is `@Disabled` because it requires a live 
server, so these offline
     cases are kept in a separate class.
   
   I confirmed the regression tests actually catch the bug by reverting only 
the `MySqlCatalog` line to
   the old `contains("unsigned")` derivation and re-running the new class. Both 
the SET and the ENUM
   case fail with the original error and nothing else changed:
   
   ```
   ErrorCode:[COMMON-17], ErrorDescription:['MySQL' unsupported convert type 
'SET UNSIGNED' of 'test' to SeaTunnel data type.]
   ErrorCode:[COMMON-17], ErrorDescription:['MySQL' unsupported convert type 
'ENUM UNSIGNED' of 'test' to SeaTunnel data type.]
   ```
   
   Then the full unit test suite of the connector:
   
   ```
   $ mvn -pl seatunnel-connectors-v2/connector-jdbc test
   Tests run: 994, Failures: 0, Errors: 4, Skipped: 6
   ```
   
   The 4 errors are Testcontainers classes that require Docker (Kingbase and 
Oracle catalog / dialect
   container tests) failing with `Previous attempts to find a Docker 
environment failed`; they do not
   touch the MySQL type conversion path and fail identically without this 
change.
   
   No E2E case is added. The trigger is a MySQL 5.7 system table shape 
(`mysql.event` / `mysql.proc`)
   that the current MySQL 8 based e2e fixtures do not reproduce, while the 
derivation and its
   conversion consequence are both covered directly by the unit tests above.
   
   ### Check list
   
   * [x] If any new Jar binary package adding in your PR, please add License 
Notice according
     [New License 
Guide](https://github.com/apache/seatunnel/blob/dev/docs/en/developer/new-license.md)
   * [x] If necessary, please update the documentation to describe the new 
feature. https://github.com/apache/seatunnel/tree/dev/docs
   * [x] If necessary, please update `incompatible-changes.md` to describe the 
incompatibility caused by this PR.
   * [x] If you are contributing the connector code, please check that the 
following files are updated:
     1. Update 
[plugin-mapping.properties](https://github.com/apache/seatunnel/blob/dev/plugin-mapping.properties)
 and add new connector information in it
     2. Update the pom file of 
[seatunnel-dist](https://github.com/apache/seatunnel/blob/dev/seatunnel-dist/pom.xml)
     3. Add ci label in 
[label-scope-conf](https://github.com/apache/seatunnel/blob/dev/.github/workflows/labeler/label-scope-conf.yml)
     4. Add e2e testcase in 
[seatunnel-e2e](https://github.com/apache/seatunnel/tree/dev/seatunnel-e2e/seatunnel-connector-v2-e2e/)
     5. Update connector 
[plugin_config](https://github.com/apache/seatunnel/blob/dev/config/plugin_config)
   


-- 
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