Map MySQL YEAR column to protocol type 0x0d so yearIsDateType driver property takes effect#38697
Map MySQL YEAR column to protocol type 0x0d so yearIsDateType driver property takes effect#38697Phixsura wants to merge 8 commits into
Conversation
terrymanu
left a comment
There was a problem hiding this comment.
Decision
Merge Verdict: Not Mergeable
Reviewed Scope: PR latest head 40b24ef; 5 changed files in database/protocol/dialect/mysql, proxy/frontend/dialect/mysql, and RELEASE-NOTES.md.
Not Reviewed Scope: Full runtime E2E execution against a live Proxy/MySQL instance was not run locally.
Need Expert Review: MySQL Proxy protocol/prepared-statement reviewer after the binary path is addressed.
Positive Feedback
The text-protocol direction is right: ResponsePacketBuilder now passes columnTypeName, and the new tests cover the adjacent YEAR vs DATE counterexample. This aligns with MySQL/Connector-J behavior: YEAR is a distinct MySQL field type, and Connector/J maps yearIsDateType=false to java.sql.Short.
Sources: PR #38697, Issue #28858, MySQL Column Definition, Connector/J YEAR handling.
Major Issues
Prepared-statement/binary path still has the same YEAR mapping gap.
The PR fixes ResponsePacketBuilder for text COM_QUERY, but MySQLProjectionMetadataResolver still builds prepared-statement projection metadata with MySQLBinaryColumnType.valueOfJDBCType(queryHeader.getColumnType()), and MySQLComStmtPrepareExecutor still uses JDBC type alone for local metadata paths. MySQLComStmtExecuteExecutor also creates BinaryCell from JDBC type only.
Risk: clients using server-side prepared statements can still receive DATE metadata for a YEAR column, so yearIsDateType=false remains ineffective on that path. MySQL binary resultsets also encode MYSQL_TYPE_YEAR as an integer value, not the date binary shape, so this needs metadata plus row-writer validation.
Recommended action: thread columnTypeName through all MySQL prepared metadata and binary row paths, then add direct regression tests for YEAR and DATE in COM_STMT_PREPARE / COM_STMT_EXECUTE.
Current validation proves the packet byte only, not the original client-visible symptom.
The added ResponsePacketBuilderTest confirms the text column-definition byte, but it does not validate the full chain: backend JDBC metadata -> QueryHeader -> row payload -> Connector/J ResultSet.getObject() with yearIsDateType=false.
Risk: the original issue is about returned Java type, and the PR body itself says another protocol path remains open. Please add either an integration reproduction or narrowly scoped protocol tests that prove both metadata and row value behavior for YEAR, including the adjacent DATE case.
Release note/title overstate the fix while binary protocol is explicitly deferred.
RELEASE-NOTES.md says the driver property takes effect for Proxy generally, but the PR text says binary protocol has the same gap and is deferred. Please either complete that path in this PR or narrow the wording and avoid closing the whole issue as fully fixed.
Next Steps
Fix or explicitly rescope the server-prepared path.
Add one-to-one tests for text Statement, server-prepared PreparedStatement, YEAR, and adjacent DATE.
Include client flags such as useServerPrepStmts=true in the prepared-statement validation.
Re-run scoped Maven with dependencies, for example ./mvnw -pl proxy/frontend/dialect/mysql,database/protocol/dialect/mysql -am -DskipITs -Dspotless.skip=true -Dtest=ResponsePacketBuilderTest,MySQLBinaryColumnTypeTest test.
terrymanu
left a comment
There was a problem hiding this comment.
Decision
- Merge Verdict: Not Mergeable
- Reviewed Scope: Latest PR head
acdfaaac3acf6ede51749d63281d942c6a0675d2; Proxy MySQL text and binary query paths;ColumnMetaData/ShardingSphereColumn/ YAML metadata propagation; MySQL metadata loader; related sharding/encrypt/broadcast/single metadata revise path by code inspection; PR #38697 and issue #28858; MySQL official YEAR / Connector/J / binary protocol docs. - Not Reviewed Scope: No local Maven run on a checked-out PR worktree; no live Proxy + MySQL Connector/J reproduction; no cluster-registry upgrade test; MariaDB client behavior not validated.
- Need Expert Review: Yes, a MySQL protocol / Connector/J reviewer should re-check the text and binary result semantics after the fixes.
Positive Feedback
- The direction is right: distinguishing MySQL
YEARfromDATEby usingcolumnTypeNameis aligned with Connector/J's documentedyearIsDateTypebehavior. - The binary-row adjustment toward a 2-byte YEAR value matches MySQL's binary protocol shape for
MYSQL_TYPE_YEAR.
Major Issues
-
[Blocking]
columnTypeNameis dropped by shared metadata revision (infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/column/ColumnReviseEngine.java:59)- Symptom: This PR adds
ColumnMetaData.columnTypeNameandShardingSphereColumn.columnTypeName, andMySQLMetaDataLoaderfills it fromDATA_TYPE; however,ColumnReviseEnginereconstructs every revised column with the old 8-argument constructor, so the new field becomesnull. - Risk:
TableMetaDataReviseEngineinvokes this path for rule-based metadata revision, and sharding/encrypt/broadcast/single all haveMetaDataReviseEntryimplementations. After revision,MySQLComStmtPrepareExecutorreadscolumn.getColumnTypeName()at lines 145, 170, and 207, so a MySQLYEARcolumn can fall back to protocolDATEin prepared-statement metadata under feature-rule topologies. That leaves a shared-path regression in the same Proxy + MySQL metadata area as the linked issue. - Action: Please preserve
each.getColumnTypeName()when rebuildingColumnMetaData, and add regression coverage for a MySQLYEARcolumn after metadata revision, at least through a sharding-rule metadata path that reachesCOM_STMT_PREPARE.
- Symptom: This PR adds
-
[Blocking] The original text-query symptom is still only metadata-tested, not row-path-tested (
database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/text/MySQLTextResultSetRowPacket.java:60)- Symptom:
ResponsePacketBuilderTestnow checks the column-definition type byte, but the issue usesStatement.executeQuery(...). That path still passes raw row values intoMySQLTextResultSetRowPacket, whose writer serializes non-special values withdata.toString()and has no column-type context. For a backendjava.sql.Datevalue, that can emitYYYY-MM-DD, while MySQL documentsYEARdisplay asYYYY. - Risk: Connector/J documents that
yearIsDateType=falsemapsYEARtojava.sql.Short, but the PR does not prove the original Proxy text protocol path returnsShort; it proves only that the metadata byte changes. This is unresolved root-cause evidence, especially forYEARzero-value behavior where Connector/J has documented special cases. - Action: Please add a regression that exercises the original
COM_QUERYpath end-to-end, or an equivalent packet-level test with row payload validation, provingYEARreturns aShortwithyearIsDateType=falsewhile normalDATEremains date-like. If the text writer emits the wrong value, thread column type context into row serialization or adjust YEAR values before writing.
- Symptom:
Newly Introduced Issues
- The metadata propagation gap above is introduced by adding a new shared metadata field without preserving it in the shared metadata-revision path.
Next Steps
- Preserve
columnTypeNameinColumnReviseEngineand add focused tests for revised metadata. - Add original-issue coverage for Proxy MySQL
COM_QUERYwithyearIsDateType=false. - Add a prepared-statement regression where local metadata is used after sharding/encrypt/single metadata revision.
- Keep DATE counterexamples in the tests so
DATEdoes not becomeYEARaccidentally. - Re-run scoped checks with dependent modules included, for example affected-module tests with
-am, then Spotless and Checkstyle.
Evidence Supplement
- PR evidence: apache/shardingsphere#38697, latest head
acdfaaac3acf6ede51749d63281d942c6a0675d2, 16 files changed. - Issue evidence: apache/shardingsphere#28858 reports Proxy + MySQL Connector/J 8 with
yearIsDateType=false. - Official behavior evidence: MySQL Connector/J documents
yearIsDateType=falsemappingYEARtojava.sql.Short; MySQL documentsYEARdisplay asYYYY; MySQL binary protocol documentsMYSQL_TYPE_YEARas a 2-byte integer. - CI evidence: GitHub API reported 83 successful check runs on the latest head, but CI success does not close the root-cause and blast-radius gaps above.
- Local commands used for review:
git fetch apache pull/38697/head:refs/remotes/apache/pr/38697 --no-tagsexit 0;git diff --name-status 579de83cf84b1c3523380b845781a45a0f54c13a...refs/remotes/apache/pr/38697exit 0;git show/git grepinspections exit 0.
terrymanu
left a comment
There was a problem hiding this comment.
Decision
- Merge Verdict: Not Mergeable
- Reviewed Scope: Latest PR head
8125cf9daeceb2de8439c263ca0d2f3d2279c170; MySQL Proxy text and binary query paths; prepared-statement metadata paths;ColumnMetaData/ShardingSphereColumn/ YAML metadata propagation; sharding metadata revise test; release note; prior GitHub-visible review feedback. - Not Reviewed Scope: No live Proxy + MySQL Connector/J reproduction; no Maven test run; no cluster-registry upgrade test; no GitHub Actions / check-run evidence used.
- Need Expert Review: Yes, MySQL protocol / Connector-J behavior should be rechecked after the remaining fixes.
Positive Feedback
- The latest revisions move in the right direction:
columnTypeNameis now preserved throughColumnReviseEngine, the textCOM_QUERYrow path handlesDate-backedYEAR, and the binary path now advertisesMYSQL_TYPE_YEARfor(Types.DATE, "YEAR").
Major Issues
-
[Blocking] Binary YEAR row serialization still fails for
Shortvalues (proxy/frontend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/execute/MySQLComStmtExecuteExecutor.java:164)- Symptom: The new binary-row adjustment converts only
java.sql.Dateto an integer year. If the backend or merged result already providesShort, it is passed unchanged intoBinaryCell;MySQLInt2BinaryProtocolValue.write(...)then casts the value toIntegeratdatabase/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLInt2BinaryProtocolValue.java:36. - Risk: Connector/J documents that
yearIsDateType=falsemapsYEARtojava.sql.Short, andJDBCStreamQueryResultcan return rawresultSet.getObject(...)atinfra/executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/result/query/impl/driver/jdbc/type/stream/JDBCStreamQueryResult.java:123. A validYEARvalue can therefore hit the prepared/binary result path asShortand fail withClassCastExceptioninstead of returning a row. - Action: Please normalize
YEARvalues from anyNumberto anintbefore writing the binary packet, and add a regression test usingnew QueryResponseCell(Types.DATE, Short.valueOf((short) 1925), "YEAR"), alongside the existingDateand adjacentDATEcases.
- Symptom: The new binary-row adjustment converts only
-
[Blocking]
COM_STMT_PREPAREYEAR metadata is changed but still not directly validated (proxy/frontend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/prepare/MySQLComStmtPrepareExecutor.java:145)- Symptom: The PR now uses
column.getColumnTypeName()for parameter marker metadata and local projection metadata at lines 145 and 207, and also changes the JDBC-probe resolver. However,MySQLComStmtPrepareExecutorTeststill uses onlyid,name, andagemetadata in its schema fixture atproxy/frontend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/prepare/MySQLComStmtPrepareExecutorTest.java:347, and there is noYEARcase in the prepared test package. - Risk: The earlier blocker was specifically about the server-prepared path. Current tests cover text response packets and
COM_STMT_EXECUTErow bytes, but they do not prove thatCOM_STMT_PREPAREreturns type byte0x0dforSELECT t_year ...,WHERE t_year = ?, or the JDBC-probe metadata path. - Action: Please add direct prepared-statement tests for local schema metadata and probe metadata, asserting
YEAR -> 0x0dand the adjacentDATE -> 0x0acounterexample.
- Symptom: The PR now uses
Next Steps
- Normalize numeric
YEARrow values in the binary writer beforeMySQLInt2BinaryProtocolValuesees them. - Add
COM_STMT_PREPAREtests forYEARprojection metadata and parameter marker metadata. - Keep the existing
DATEcounterexamples so normal dates do not accidentally becomeYEAR. - After fixes, run affected-module tests with dependencies, for example
./mvnw -pl proxy/frontend/dialect/mysql,database/protocol/dialect/mysql,infra/common,features/sharding/core,database/connector/dialect/mysql -am -DskipITs -Dspotless.skip=true -Dtest=MySQLComStmtPrepareExecutorTest,MySQLComStmtExecuteExecutorTest,MySQLComQueryPacketExecutorTest,ResponsePacketBuilderTest,MySQLBinaryColumnTypeTest,ColumnReviseEngineTest,ShardingMetaDataReviseEntryTest,MySQLMetaDataLoaderTest test.
Multi-Round Comparison
- Fixed: The shared metadata-revision loss from the previous review is addressed by preserving
each.getColumnTypeName()inColumnReviseEngine, with an added sharding revise-path test. - Partially fixed: The binary/prepared path now threads
columnTypeNameand testsDate-backed binary rows, but it still misses the validShortproducer path. - Partially fixed: Text
COM_QUERYnow validates row payload for aDate-backedYEAR; this no longer remains the primary blocker in the latest head. - Not fixed: Direct
COM_STMT_PREPAREvalidation forYEARmetadata is still missing.
Evidence Supplement
- PR evidence: apache/shardingsphere#38697, latest head
8125cf9daeceb2de8439c263ca0d2f3d2279c170. - Issue evidence: apache/shardingsphere#28858 reports Proxy + MySQL Connector/J 8 with
yearIsDateType=false, expectingShort. - Official behavior evidence: Connector/J YEAR handling documents the
yearIsDateType=falsemapping; MySQL protocol field types listMYSQL_TYPE_YEARseparately fromMYSQL_TYPE_DATE. - Local inspection commands:
git fetch apache pull/38697/head:refs/remotes/apache/pr/38697exit 0;git diff --name-only apache/master...apache/pr/38697exit 0;git grep -n "YEAR\\|year" apache/pr/38697 -- proxy/frontend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/prepare || trueexit 0 with no prepared-path YEAR tests found. - Local Maven verification was not run because the static review found blocking functional and coverage gaps first.
|
B1 已修。 B2 已修。
Head
|
|
Please resolve conflict first |
…property takes effect
…inary row writer so YEAR columns map to protocol type 0x0d on both text and binary paths
…revision and adjust YEAR Date row value to a four-digit year string on the text COM_QUERY path so prepared-statement metadata under sharding rules and Statement.executeQuery both return MySQL YEAR semantics
…ta passed through TableMetaDataReviseEngine keeps its columnTypeName for downstream prepared-statement metadata
…YEAR vs DATE projections and parameter markers across local-schema and probe prepared-statement metadata paths so Short payloads serialize as protocol type 0x0d
ab9fdb6 to
1e42d9b
Compare
terrymanu
left a comment
There was a problem hiding this comment.
Decision
- Merge Verdict: Not Mergeable
- Reviewed Scope: Latest PR head
1e42d9b7fa94debfb504fdcec82cf1c4a70f0212; local merge-basea9ac265ad4adcc247a8af27f1febca026e6cc8d4; GitHub/pulls/38697/filesmatched the local 22-file triple-dot diff exactly. Reviewed Proxy MySQL text/binary query paths, prepared metadata, MySQL protocol type mapping, MySQL metadata loading, shared schema metadata/YAML propagation, sharding metadata revision coverage, release note, issue #28858, and prior GitHub-visible review feedback. - Not Reviewed Scope: No live Proxy + MySQL Connector/J reproduction, no cluster-registry upgrade test, and no local Maven test run because the static review found an unresolved functional boundary first. GitHub Actions / CI status was not used.
- Need Expert Review: Yes, MySQL protocol / Connector-J semantics should be rechecked after the remaining YEAR zero-value fix.
Positive Feedback
- The latest revision fixes several previous blockers:
columnTypeNameis preserved through shared metadata revision,COM_STMT_PREPAREnow has direct YEAR vs DATE metadata tests, and binary row writing now normalizesNumberYEAR values before the 2-byte protocol writer. - Mapping
(Types.DATE, "YEAR")toMYSQL_TYPE_YEARis directionally correct and matches the documented Connector/JyearIsDateType=falsegoal.
Major Issues
- [Blocking] YEAR zero values can still be returned with the wrong client-visible value (
proxy/frontend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/text/query/MySQLComQueryPacketExecutor.java:147)- Symptom: The new text path only converts
java.sql.DateYEAR values toString.format("%04d", dateYear). If the row value is already aNumber,MySQLTextResultSetRowPacketstill falls through todata.toString()atdatabase/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/text/MySQLTextResultSetRowPacket.java:89, soShort.valueOf((short) 0)is sent as"0"instead of MySQL'sYEARdisplay value"0000". On the default backend path,MySQLResultSetMapper#getDateValuereads YEAR viaresultSet.getObject(...)atdatabase/connector/dialect/mysql/src/main/java/org/apache/shardingsphere/database/connector/mysql/resultset/MySQLResultSetMapper.java:38, and the MySQL default query properties do not set backendyearIsDateType=falseatdatabase/connector/dialect/mysql/src/main/java/org/apache/shardingsphere/database/connector/mysql/jdbcurl/MySQLDefaultQueryPropertiesProvider.java:31; therefore a backendYEAR 0000can already be collapsed by Connector/J intoDate(2000-01-01). The binary path has the same Date-to-year collapse atproxy/frontend/dialect/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/binary/execute/MySQLComStmtExecuteExecutor.java:164. - Risk: The original issue is about Connector/J client-visible YEAR behavior. Official Connector/J docs say
yearIsDateType=falsemaps YEAR tojava.sql.Short, and its zero-value rules distinguish numeric0from2000; MySQL docs also say YEAR displays inYYYYformat and includes0000. This PR can makeYEAR 0000arrive asShort 2000, or as text"0"on the Number-backed path, so the root-cause repair is still incomplete for a valid boundary value. - Action: Please preserve YEAR's raw value before it is collapsed into
java.sql.Date, or otherwise normalize YEAR rows from bothDateandNumberforms to native MySQL semantics. Add direct regressions forYEAR 0000,YEAR 2000, and adjacentDATEon bothCOM_QUERYandCOM_STMT_EXECUTE; text protocol should emit0000for zero YEAR, and binary protocol should write the 2-byte integer0.
- Symptom: The new text path only converts
Newly Introduced Issues
- The zero-value drift is introduced by the new YEAR row conversion logic: the patch now advertises
MYSQL_TYPE_YEAR, but the row payload conversion still does not prove native YEAR zero semantics.
Next Steps
- Add zero-value tests for text and binary YEAR rows, including
Short 0,Date(2000-01-01), realYEAR 2000, and adjacent normalDATE. - Adjust the MySQL YEAR extraction/conversion path so
0000remains distinguishable from2000. - Keep the existing YEAR vs DATE metadata tests; they are useful and should remain.
- After the fix, run scoped verification with dependencies, for example:
./mvnw -pl proxy/frontend/dialect/mysql,database/protocol/dialect/mysql,database/connector/dialect/mysql,infra/common,features/sharding/core -am -DskipITs -Dspotless.skip=true -Dtest=MySQLComQueryPacketExecutorTest,MySQLComStmtExecuteExecutorTest,MySQLComStmtPrepareExecutorTest,ResponsePacketBuilderTest,MySQLBinaryColumnTypeTest,MySQLMetaDataLoaderTest,ColumnReviseEngineTest,ShardingMetaDataReviseEntryTest test, then run the repository Spotless and Checkstyle gates.
Multi-Round Comparison
- Fixed: The shared metadata-revision loss is addressed by preserving
columnTypeNameinColumnReviseEngine. - Fixed: The previous
Shortbinary-rowClassCastExceptionrisk is addressed by normalizingNumberYEAR values. - Fixed: Direct
COM_STMT_PREPAREYEAR metadata coverage was added for local schema, parameter marker, and probe metadata paths. - Newly introduced / unresolved: Valid zero YEAR semantics remain unproven and can still diverge from native MySQL + Connector/J behavior.
Evidence Supplement
- Issue evidence: apache/shardingsphere#28858 targets ShardingSphere-Proxy + MySQL Connector/J with
yearIsDateType=false. - Official behavior evidence: Connector/J YEAR handling, MySQL YEAR type, and MySQL binary protocol YEAR as int<2>.
- Local boundary evidence:
git fetch apache master +pull/38697/head:refs/remotes/apache/pr/38697exit 0; local 22-file diff matched GitHub/pulls/38697/files;git grep -n "computeIfAbsent"over changed files found no hot-pathcomputeIfAbsentusage.
…r/J returns YEAR as Short rather than collapsing zero values into Date(2000-01-01), extend the text COM_QUERY adjuster with a Number branch that formats raw YEAR values as %04d for parity with the existing Date branch, and cover YEAR 0000 plus YEAR 2000 and adjacent DATE through Short-backed semantics on both COM_QUERY and COM_STMT_EXECUTE so native MySQL display behavior survives both protocols at the zero boundary
|
Please resolve conflicts first |
|
Hi @Phixsura, thanks again for the continued updates on this PR. The fix direction looks reasonable, and the latest revisions have addressed several previous YEAR metadata and row-serialization concerns. However, this PR is currently not ready for review or merge because it has conflicts with the target branch, and the latest maintainer feedback asked to resolve conflicts first. Could you please rebase this PR and resolve the conflicts? After that, we can continue the focused review on the MySQL YEAR protocol behavior. To keep the review queue clear, we may close this PR soon due to inactivity if there is still no response or update. Thanks again for your contribution. |
Fixes #28858.
Changes proposed in this pull request:
MySQLBinaryColumnType.valueOfJDBCType(int, String)and anisYearhelper that recognises(Types.DATE, "YEAR")and returns theYEARenum, mirroring the existingPostgreSQLBinaryColumnTypeoverload pattern.ResponsePacketBuilder) to the new overload, threadingQueryHeader#getColumnTypeName()so a MySQLYEARcolumn is advertised as protocol type0x0dinstead ofDATE(0x0a). mysql-connector-j now enters its YEAR branch and the driver-sideyearIsDateType=falseURL property takes effect.ResponsePacketBuilderTest: the parametric case now asserts the on-wire column-type byte for every row, with new rows pinning YEAR →0x0dand DATE →0x0a.The binary (prepared-statement) protocol path has the same gap but needs a paired writer change (
java.sql.Date→ 2-byte short forMySQLInt2BinaryProtocolValue); sending that as a separate follow-up rather than crammed into this one.Before committing this PR, I'm sure that I have checked the following options: