Doris-Breakwater commented on issue #66953:
URL: https://github.com/apache/doris/issues/66953#issuecomment-5341117735

   Breakwater-GitHub-Analysis-Slot: slot_7de645b9cb28
   
   Initial assessment: this is not a simple type-name bug in v4.1.3. The 
reported `CHAR` metadata is intentional for the MySQL wire protocol, but the 
report exposes a real client-compatibility limitation for Go/GORM callers that 
scan a `TIMESTAMPTZ` result directly into `time.Time`.
   
   Verified facts:
   
   - In the v4.1.3 source, [`PrimitiveType.TIMESTAMPTZ` maps to 
`MYSQL_TYPE_STRING`](https://github.com/apache/doris/blob/4.1.3/fe/fe-common/src/main/java/org/apache/doris/catalog/PrimitiveType.java#L430-L431).
 That protocol type is code 254 and Doris names it `CHAR` in 
[`MysqlColType`](https://github.com/apache/doris/blob/4.1.3/fe/fe-common/src/main/java/org/apache/doris/catalog/MysqlColType.java#L56-L58).
 Therefore, `DatabaseTypeName() == "CHAR"` is consistent with the metadata 
Doris sends; it is not a GORM-only renaming.
   - This was a deliberate fix in [PR 
#63292](https://github.com/apache/doris/pull/63292). Doris previously 
advertised the value as MySQL `DATETIME`, while the row payload was actually a 
length-encoded, timezone-aware string such as `yyyy-MM-dd 
HH:mm:ss[.ffffff]+HH:mm`. Server-prepared Connector/J queries consequently 
tried to decode string bytes as a MySQL temporal binary value and failed. The 
fix aligned the metadata with the existing string payload and added text/binary 
protocol coverage.
   - The standard MySQL column-definition type enum has no distinct 
`TIMESTAMPTZ` type code. Merely changing the advertised type to 
`TIMESTAMP`/`DATETIME` without also changing the payload and defining the 
timezone semantics would reintroduce a metadata/payload mismatch. A MySQL 
temporal binary value also has no field for the rendered UTC offset.
   - The commonly used `go-sql-driver/mysql` maps MySQL `fieldTypeString` to 
[`DatabaseTypeName() == 
"CHAR"`](https://github.com/go-sql-driver/mysql/blob/master/fields.go#L795-L812).
 Such a column is normally delivered as bytes/string, not `time.Time`; 
`parseTime=true` only affects MySQL temporal column types, so it does not by 
itself make this direct `TIMESTAMPTZ` scan work.
   
   Likely failure mechanism (not yet fully verified for this report): GORM is 
receiving a string/`[]byte` for the column and `database/sql` cannot assign 
that directly to the struct's `time.Time` field. The issue does not include the 
exact driver, versions, DSN, or scan error, so we should not claim that this is 
the reporter's exact path until those details are supplied.
   
   Information needed from the reporter:
   
   1. The GORM dialect/import path and version, underlying Go SQL driver and 
version, and a redacted DSN (especially `parseTime`, `loc`, and whether native 
prepared statements are used).
   2. The exact DDL, insert value, SELECT, struct definition, and complete 
error text.
   3. A minimal `database/sql` reproduction without GORM that prints 
`rows.ColumnTypes()` (`DatabaseTypeName`, `ScanType`) and attempts both 
`Scan(&stringValue)` and `Scan(&timeValue)`.
   4. Whether the failure occurs with a normal text query, a 
server-prepared/binary query, or both, plus `SELECT @@time_zone` and one raw 
string value returned for the column.
   5. The required semantic contract: must the returned value preserve the 
explicit offset, or is a session-time-zone wall-clock `time.Time` with the 
offset removed acceptable?
   
   Suggested next steps:
   
   - Treat this as a MySQL-protocol/Go-client compatibility or feature-design 
issue rather than reverting the existing mapping immediately. The issue 
currently has no labels; a compatibility/enhancement classification is more 
accurate unless the requested evidence shows a different payload bug.
   - For an immediate workaround that preserves the offset, scan into `string`, 
`sql.NullString`, or a custom `sql.Scanner`/GORM data type and parse Doris's 
offset-aware textual form. If losing the explicit offset is acceptable, test 
`CAST(ts AS DATETIMEV2(6))` with `parseTime=true`; this uses the session 
timezone, so the semantic tradeoff must be explicit.
   - If automatic `time.Time` support is adopted, design it as a 
protocol-compatible contract rather than only changing `DatabaseTypeName`. Add 
Go integration tests for both text and prepared/binary queries, checking 
`ColumnTypes()`, direct scanning, NULL, fractional precision, positive/negative 
offsets, and session-time-zone conversion. An opt-in conversion/cast may be 
safer than changing the current offset-preserving result contract for every 
MySQL client.
   


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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to