terrymanu commented on issue #34289:
URL: 
https://github.com/apache/shardingsphere/issues/34289#issuecomment-3677368199

   ##  Problem Understanding
   
     - On Proxy 5.5.1, a Golang client executes a prepared query (e.g., ... 
limit ?, ?) and hits an NPE in MySQLComStmtExecuteExecutor; deeper inspection 
shows the failure starts with a ClassCastException during parameter binding.
     - Trigger: the client sends parameters via MySQL binary protocol with 
LIMIT arguments marked as string-like types; the protocol layer returns raw 
byte[]/String, while downstream expects numeric types and fails to cast.
   
   ##  Root Cause
   
     - In MySQL protocol execution (MySQLComStmtExecutePacket#readParameters), 
string-type parameters (e.g., MYSQL_TYPE_STRING/VAR_STRING) are returned as-is 
(byte[]/String) with no type normalization.
     - Binding logic (e.g., PaginationContext#getValue and any path that needs 
numbers) only accepts Number. Receiving byte[]/String triggers a 
ClassCastException, which bubbles up and shows as an NPE in 
MySQLComStmtExecuteExecutor.
     - Essentially, the protocol layer doesn’t normalize binary-protocol 
parameters to Java types consistent with their declared types/semantics; it 
assumes parameters are already correct numerics.
   
   ##  Problem Analysis
   
     - For non-INSERT statements, prepare phase defaults parameter column 
definitions to VAR_STRING, so clients may send all params as strings.
     - MySQLBinaryProtocolValueFactory returns byte[]/String for string/byte 
types and doesn’t align with SQL semantics (e.g., numeric usage).
     - Binding cannot distinguish “string param” vs “numeric-meaning string”; 
any numeric-expected path (not just pagination) will fail if the param comes 
back as a string.
     - Relevant official protocol doc (COM_STMT_EXECUTE and data types): 
https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_execute.html
   
     Conclusion (Code-Design-Level Fix Suggestion, Protocol-Layer General 
Handling)
   
     - Fix at the protocol layer by normalizing all parameters once after 
reading, before binding, using MySQL parameter types (and unsigned flags) plus 
column definition flags:
   
       // Design sketch: after readParameters and before bindParameters
       List<Object> params = packet.readParameters(...);
       List<MySQLPreparedStatementParameterType> types = 
preparedStatement.getParameterTypes();
       List<Integer> flags = 
preparedStatement.getParameterColumnDefinitionFlags();
   
       List<Object> normalized = new ArrayList<>(params.size());
       for (int i = 0; i < params.size(); i++) {
           Object val = params.get(i);
           MySQLPreparedStatementParameterType type = types.get(i);
           int flag = flags.isEmpty() ? 0 : flags.get(i);
           normalized.add(normalizeValue(type, flag, val)); // Number stays 
Number; byte[]/CharSequence parsed to Number when the type is numeric; 
non-numeric text throws a clear SQLException
       }
       // then bindParameters(normalized)
         - Use MySQL type + unsigned flag + column definition flag to decide 
the target Java type; keep true character types as-is, but for numeric types 
(even if sent as VAR_STRING) parse safely to Long/BigDecimal, throwing a 
readable error on invalid format.
         - Do the normalization once in the protocol execution path to avoid 
scattering type assumptions in higher layers.
         - Tests:
             - Numeric params (including unsigned) come back as correct Number.
             - VAR_STRING/VARBINARY marked as numeric columns: numeric text in 
byte[]/String parses successfully; non-numeric text throws a clear exception.
             - Pure string types remain unchanged.
             - Paths that need numerics (including LIMIT) no longer throw 
type-cast errors.
   
     We warmly invite community contributors to submit a PR implementing this 
protocol-layer normalization and adding the above tests, especially to improve 
robustness for Golang clients using prepared statements. Your help is highly 
appreciated!


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