Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
3.2.8
-
None
-
macOS Tahoe 26.4.1
Description
Summary
According to the ODBC documentation for the COLUMN_SIZE column returned by SQLGetTypeInfo: "For datetime data types, this is the length incharacters of the string representation (assuming the maximum allowed precision of the fractional seconds component)." However, with the MariaDB ODBC connector:
TYPE_NAME COLUMN_SIZE
|
-------------------------------- -----------
|
DATETIME 16
|
TIMESTAMP 16
|
This causes sub-second precision to be discarded for datetime objects passed as parameters using pyodbc.
Repro
To verify this behavior, compile and run this code, providing the connection string as the command-line argument.
#include <stdio.h>
|
#include <stdlib.h>
|
#include <sql.h>
|
#include <sqlext.h>
|
|
|
static void check(SQLRETURN ret, SQLSMALLINT htype, SQLHANDLE h, const |
char* msg) |
{
|
if (SQL_SUCCEEDED(ret)) |
return; |
SQLCHAR state[6], text[256];
|
SQLINTEGER native;
|
SQLSMALLINT len;
|
SQLGetDiagRec(htype, h, 1, state, &native, text, sizeof(text), |
&len);
|
fprintf(stderr, "ERROR %s: %s (%s, native=%d)\n", msg, text, state, |
native);
|
exit(1); |
}
|
|
|
int main(int argc, char* argv[]) |
{
|
if (argc < 2) { |
fprintf(stderr, "Usage: %s <connection-string>\n", argv[0]); |
return 1; |
}
|
|
|
printf("sizeof(SQL_TIMESTAMP_STRUCT) = %zu\n", |
sizeof(SQL_TIMESTAMP_STRUCT)); |
|
|
SQLHENV henv = SQL_NULL_HANDLE;
|
SQLHDBC hdbc = SQL_NULL_HANDLE;
|
SQLHSTMT hstmt = SQL_NULL_HANDLE;
|
SQLRETURN ret;
|
|
|
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
|
check(ret, SQL_HANDLE_ENV, henv, "SQLAllocHandle(ENV)"); |
|
|
ret = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
|
(SQLPOINTER)SQL_OV_ODBC3, 0);
|
check(ret, SQL_HANDLE_ENV, henv, "SQLSetEnvAttr"); |
|
|
ret = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
|
check(ret, SQL_HANDLE_ENV, henv, "SQLAllocHandle(DBC)"); |
|
|
ret = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)argv[1], SQL_NTS,
|
NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
|
check(ret, SQL_HANDLE_DBC, hdbc, "SQLDriverConnect"); |
|
|
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
|
check(ret, SQL_HANDLE_DBC, hdbc, "SQLAllocHandle(STMT)"); |
|
|
ret = SQLGetTypeInfo(hstmt, SQL_TYPE_TIMESTAMP);
|
check(ret, SQL_HANDLE_STMT, hstmt, "SQLGetTypeInfo"); |
|
|
printf("%-32s %s\n", "TYPE_NAME", "COLUMN_SIZE"); |
printf("%-32s %s\n", "--------------------------------", |
"-----------"); |
|
|
while (SQL_SUCCEEDED(SQLFetch(hstmt))) |
{
|
SQLCHAR type_name[128];
|
SQLLEN type_name_ind;
|
SQLINTEGER column_size;
|
SQLLEN column_size_ind;
|
|
|
ret = SQLGetData(hstmt, 1, SQL_C_CHAR, type_name,
|
sizeof(type_name), &type_name_ind); |
check(ret, SQL_HANDLE_STMT, hstmt, "SQLGetData(TYPE_NAME)"); |
|
|
ret = SQLGetData(hstmt, 3, SQL_C_SLONG, &column_size,
|
sizeof(column_size), &column_size_ind); |
check(ret, SQL_HANDLE_STMT, hstmt, "SQLGetData(COLUMN_SIZE)"); |
|
|
if (column_size_ind == SQL_NULL_DATA) |
printf("%-32s NULL\n", type_name); |
else |
printf("%-32s %d\n", type_name, column_size); |
}
|
|
|
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
|
SQLDisconnect(hdbc);
|
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
|
SQLFreeHandle(SQL_HANDLE_ENV, henv);
|
return 0; |
}
|
You can also see the effect of the bug with this Python script:
import argparse |
import datetime |
import pyodbc |
|
|
VALUE = datetime.datetime(2000, 1, 2, 3, 4, 5, 123456) |
|
|
parser = argparse.ArgumentParser() |
parser.add_argument("conn") |
args = parser.parse_args() |
conn = pyodbc.connect(args.conn) |
cursor = conn.cursor() |
cursor.execute("CREATE TEMPORARY TABLE truncated_datetime_repro (dt
|
datetime(6))") |
cursor.execute("INSERT INTO truncated_datetime_repro VALUES (?)", |
VALUE)
|
cursor.execute("SELECT dt FROM truncated_datetime_repro") |
print("expected:", VALUE) |
print(" got:", cursor.fetchval()) |
Output
expected: 2000-01-02 03:04:05.123456
|
got: 2000-01-02 03:04:05
|
Recommendation
Return 26 for the COLUMN_SIZE, reflecting the MariaDB documentation which says that
MariaDB displays DATETIME values in 'YYYY-MM-DD HH:MM:SS.ffffff' format.
Attachments
Issue Links
- relates to
-
ODBC-430 Wrong reported max size for VARCHAR and VARBINARY
-
- Closed
-