Details
-
Bug
-
Status: Open (View Workflow)
-
Major
-
Resolution: Unresolved
-
None
-
None
-
Tested on Ubuntu Server, Arch Linux
Description
- I believe this regression was introduced in commit 40806da9 (follow-up to
CONC-8125fe4d03f), present in the libmariadb bundled with MariaDB server 12.3.2 (64e9fe0). The bug is absent in 12.2.2 (7bb4e6c). I believe that is also absent in in 12.3.1, but the versions I tested for the regression were 12.3.2 and 12.2.2. It would presumably also be present in the yet-to-be-released
3.4.9 Connector/C.
tl;dr it seems that mysql_stmt_bind_result() clobbers caller-provided pointers for buffer length to 0 after the above commit (for temporal columns), breaking the C API's docs promise of this value containing the actual retrieved length.
===
Given a prepared SELECT of a DATETIME column, with the client binding a result buffer of buffer_type = MYSQL_TYPE_DATETIME (a MYSQL_TIME buffer) and supplying its own length pointer (the C-API documents length as receiving the actual fetched length):
1. Client binds the result: bind.buffer_type = MYSQL_TYPE_DATETIME, bind.buffer = &tm, bind.buffer_length = sizeof(MYSQL_TIME), bind.length = &my_len (with my_len pre-initialized by the caller).
2. mysql_stmt_bind_result() runs the per-column initialization added in commit 40806da9:
if (mysql_ps_fetch_functions[bind[i].buffer_type].pack_len >= 0) |
*bind[i].length = bind[i].length_value = pack_len; /* fixed-size numerics */ |
else
|
*bind[i].length = bind[i].length_value = 0; /* everything else */ |
3. The temporal types are registered with pack_len = MYSQL_PS_SKIP_RESULT_W_LEN (a negative sentinel value), so they take the else branch -> *bind.length is overwritten to 0, clobbering the caller's length value.
4. mysql_stmt_fetch() -> mthd_stmt_fetch_to_bind(). For a bound, non-NULL temporal column it dispatches to ps_fetch_datetime(), which correctly decodes the wire bytes into the MYSQL_TIME buffer. This bound-result path does not write *bind.length, so *bind.length remains 0.
5. bind.buffer holds the correct MYSQL_TIME (e.g. 2014-07-28 15:28:47), *bind.is_null == 0, but *bind.length == 0. A client that trusts length (per the documented fetch semantics, it should hold the number of bytes of the fetched value) concludes the column has no data and discards the otherwise valid value.
The net change from <= 3.4.8: the old per-type switch in mysql_stmt_bind_result() left temporal columns length untouched; the new pack_len-based init zeroes them. Combined with the fetch path not setting length for bound temporal columns, the caller-visible length for a present DATE/DATETIME is now always 0.
Attachments
Issue Links
- relates to
-
CONC-812 Length for fixed-size types can be set incorrectly by mysql_stmt_fetch
-
- Closed
-