Skip to content

Commit 8ff6c0f

Browse files
committed
ODBC-449 Fractional seconds could be lost with SQLExecDirect
That happend that with text protocol fractional part wasn't internally converted to microseconds as it's expected by functions converting data to ODBC structures. Natuarally, binary protocol, i.e. (SQLPrepare + SQLExecute) were not affected. The commit contains the testcase.
1 parent 61faaee commit 8ff6c0f

File tree

4 files changed

+74
-42
lines changed

4 files changed

+74
-42
lines changed

driver/interface/ResultSet.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,27 @@ namespace mariadb
342342
time->second= static_cast<uint32_t>(std::stoll(str.substr(offset + 6, 2)));
343343
time->second_part= 0;
344344
if (str[offset + 8] == '.') {
345-
time->second_part= static_cast<uint32_t>(std::stoll(str.substr(offset + 9, std::min(str.length() - offset - 9, static_cast<std::size_t>(6)))));
345+
auto fractPartLen= std::min(str.length() - offset - 9, std::size_t(6));
346+
time->second_part= static_cast<unsigned long>(std::stoll(str.substr(offset + 9, fractPartLen)));
347+
// Need to make it microseconds
348+
switch (fractPartLen) {
349+
case 1:
350+
time->second_part*= 10000;
351+
break;
352+
case 2:
353+
time->second_part*= 10000;
354+
break;
355+
case 3:
356+
time->second_part*= 1000;
357+
break;
358+
case 4:
359+
time->second_part*= 100;
360+
break;
361+
case 5:
362+
time->second_part*= 10;
363+
default:
364+
break;
365+
}
346366
}
347367
}
348368

driver/ma_helper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,7 @@ SQLRETURN MADB_CopyMadbTimestamp(MADB_Stmt *Stmt, MYSQL_TIME *tm, SQLPOINTER Dat
742742
ts->year= tm->year;
743743
ts->month= tm->month;
744744
ts->day= tm->day;
745+
// Microseconds of MYSQL_TIME to nanoseconds of SQL_TIMESTAMP_STRUCT
745746
ts->fraction= tm->second_part * 1000;
746747
}
747748
ts->hour= tm->hour;

test/datetime.c

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1523,7 +1523,7 @@ ODBC_TEST(t_odbc199_time2timestamp)
15231523
SQL_TIME_STRUCT t;
15241524
SQL_TIMESTAMP_STRUCT ts= {0}, ts1= {0};
15251525
time_t sec_time;
1526-
struct tm * cur_tm;
1526+
struct tm *cur_tm;
15271527

15281528
sec_time= time(NULL);
15291529
cur_tm= localtime(&sec_time);
@@ -1641,6 +1641,56 @@ ODBC_TEST(t_odbc345)
16411641
}
16421642

16431643

1644+
ODBC_TEST(t_odbc449)
1645+
{
1646+
SQL_TIMESTAMP_STRUCT ts= {0}, r1= {0};
1647+
unsigned long fractional[]= {0,100000000,120000000,20000000,23000000,3000000,0};
1648+
char asStr[32];
1649+
size_t rowNum= 0;
1650+
1651+
ts.year= 2025;
1652+
ts.month= 1;
1653+
ts.day= 1;
1654+
ts.hour= 12;
1655+
ts.minute= 0;
1656+
ts.second= 0;
1657+
ts.fraction= 123000000;
1658+
1659+
OK_SIMPLE_STMT(Stmt, "DROP TABLE IF EXISTS t_odbc449");
1660+
OK_SIMPLE_STMT(Stmt, "CREATE TABLE t_odbc449 (dtf DATETIME(3) NOT NULL)");
1661+
1662+
CHECK_STMT_RC(Stmt, SQLExecDirect(Stmt, "INSERT INTO t_odbc449(dtf) VALUES ('2025-01-01 12:00:00.123'),('2025-01-01 12:00:00.1'),\
1663+
('2025-01-01 12:00:00.12'),('2025-01-01 12:00:00.02'),('2025-01-01 12:00:00.023'),('2025-01-01 12:00:00.003')", SQL_NTS));;
1664+
1665+
OK_SIMPLE_STMT(Stmt, "SELECT dtf FROM t_odbc449");
1666+
1667+
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 1, SQL_C_TIMESTAMP, &r1,sizeof(r1), NULL));
1668+
1669+
while (SQL_SUCCEEDED(SQLFetch(Stmt)))
1670+
{
1671+
is_num(ts.year, r1.year);
1672+
is_num(ts.month, r1.month);
1673+
is_num(ts.day, r1.day);
1674+
is_num(ts.hour, r1.hour);
1675+
is_num(ts.minute, r1.minute);
1676+
is_num(ts.second, r1.second);
1677+
is_num(ts.fraction, r1.fraction);
1678+
1679+
if (!rowNum)
1680+
{
1681+
IS_STR("2025-01-01 12:00:00.123", my_fetch_str(Stmt, asStr, 1), sizeof("2025-01-01 12:00:00.123"));
1682+
}
1683+
++rowNum;
1684+
ts.fraction= fractional[rowNum];
1685+
}
1686+
is_num(6, rowNum);
1687+
CHECK_STMT_RC(Stmt, SQLCloseCursor(Stmt));
1688+
1689+
OK_SIMPLE_STMT(Stmt, "DROP TABLE t_odbc449");
1690+
1691+
return OK;
1692+
}
1693+
16441694
MA_ODBC_TESTS my_tests[]=
16451695
{
16461696
{my_ts, "my_ts", NORMAL},
@@ -1669,6 +1719,7 @@ MA_ODBC_TESTS my_tests[]=
16691719
{t_odbc148, "t_odbc148_datatypes_values_len", NORMAL},
16701720
{t_odbc199_time2timestamp, "t_odbc199_time2timestamp", NORMAL},
16711721
{t_odbc345, "t_odbc345", NORMAL},
1722+
{t_odbc449, "t_odbc449", NORMAL},
16721723
{NULL, NULL}
16731724
};
16741725

test/relative.c

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -787,48 +787,8 @@ ODBC_TEST(t_rows_fetched_ptr1)
787787
}
788788

789789

790-
ODBC_TEST(bench)
791-
{
792-
SQLINTEGER id= 0;
793-
SQLCHAR val[32];
794-
size_t i;
795-
796-
for (i= 0; i < 500; ++i) {
797-
SQLExecDirect(Stmt, (SQLCHAR*)"SELECT * FROM 1000rows", SQL_NTS);
798-
799-
while (SQLFetch(Stmt) != SQL_NO_DATA) {
800-
SQLGetData(Stmt, 1, SQL_INTEGER, &id, 0, NULL);
801-
SQLGetData(Stmt, 2, SQL_VARCHAR, &val, sizeof(val), NULL);
802-
}
803-
SQLFreeStmt(Stmt, SQL_CLOSE);
804-
}
805-
return OK;
806-
}
807-
808-
809-
ODBC_TEST(bench1)
810-
{
811-
size_t i;
812-
813-
for (i= 0; i < 200; ++i) {
814-
SQLPrepare(Stmt, (SQLCHAR*)"DO ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?",
815-
SQL_NTS);
816-
for (int i = 1; i <= 1000; i++) {
817-
SQLBindParameter(Stmt, i, SQL_PARAM_INPUT, SQL_C_LONG,
818-
SQL_INTEGER, 0, 0, &i, 0, NULL);
819-
}
820-
// Execute query
821-
SQLExecute(Stmt);
822-
SQLFreeStmt(Stmt, SQL_CLOSE);
823-
}
824-
return OK;
825-
}
826-
827-
828790
MA_ODBC_TESTS my_tests[]=
829791
{
830-
//{bench, "bench"},
831-
//{bench1, "bench1"},
832792
{t_relative, "t_relative"},
833793
{t_relative1, "t_relative1"},
834794
{t_relative2, "t_relative2"},

0 commit comments

Comments
 (0)