diff --git a/mssql_python/pybind/ddbc_bindings.cpp b/mssql_python/pybind/ddbc_bindings.cpp index 94f62f3a..c7537cbe 100644 --- a/mssql_python/pybind/ddbc_bindings.cpp +++ b/mssql_python/pybind/ddbc_bindings.cpp @@ -247,7 +247,7 @@ struct ArrowArrayPrivateData { std::unique_ptr varVal; std::unique_ptr dateVal; std::unique_ptr tsMicroVal; - std::unique_ptr timeSecondVal; + std::unique_ptr timeNanoVal; std::unique_ptr decimalVal; std::vector varData; @@ -4691,12 +4691,10 @@ SQLRETURN FetchArrowBatch_wrap( arrowColumnProducer->dateVal = std::make_unique(arrowBatchSize); arrowColumnProducer->ptrValueBuffer = arrowColumnProducer->dateVal.get(); break; - case SQL_TIME: - case SQL_TYPE_TIME: case SQL_SS_TIME2: - format = "tts"; - arrowColumnProducer->timeSecondVal = std::make_unique(arrowBatchSize); - arrowColumnProducer->ptrValueBuffer = arrowColumnProducer->timeSecondVal.get(); + format = "ttn"; + arrowColumnProducer->timeNanoVal = std::make_unique(arrowBatchSize); + arrowColumnProducer->ptrValueBuffer = arrowColumnProducer->timeNanoVal.get(); break; case SQL_BIT: format = "b"; @@ -4965,8 +4963,6 @@ SQLRETURN FetchArrowBatch_wrap( } break; } - case SQL_TIME: - case SQL_TYPE_TIME: case SQL_SS_TIME2: { buffers.timeBuffers[idxCol].resize(1); ret = SQLGetData_ptr( @@ -5226,14 +5222,13 @@ SQLRETURN FetchArrowBatch_wrap( buffers.dateBuffers[idxCol][idxRowSql].day ); break; - case SQL_TIME: - case SQL_TYPE_TIME: case SQL_SS_TIME2: { const SQL_SS_TIME2_STRUCT& timeValue = buffers.timeBuffers[idxCol][idxRowSql]; - arrowColumnProducer->timeSecondVal[idxRowArrow] = - static_cast(timeValue.hour) * 3600 + - static_cast(timeValue.minute) * 60 + - static_cast(timeValue.second); + arrowColumnProducer->timeNanoVal[idxRowArrow] = + static_cast(timeValue.hour) * 3600 * 1000000000 + + static_cast(timeValue.minute) * 60 * 1000000000 + + static_cast(timeValue.second) * 1000000000 + + static_cast(timeValue.fraction); break; } case SQL_BIT: { diff --git a/tests/test_004_cursor_arrow.py b/tests/test_004_cursor_arrow.py index 0f3b9d13..ce6163f6 100644 --- a/tests/test_004_cursor_arrow.py +++ b/tests/test_004_cursor_arrow.py @@ -89,15 +89,20 @@ def get_arrow_test_data(include_lobs: bool, batch_length: int): ], ), ( - pa.time32("s"), + pa.time64("ns"), "time(0)", [time(12, 0, 5, 0), None, time(23, 59, 59, 0), time(0, 0, 0, 0)], ), ( - pa.time32("s"), + pa.time64("ns"), "time(7)", [time(12, 0, 5, 0), None, time(23, 59, 59, 0), time(0, 0, 0, 0)], ), + ( + pa.time64("ns"), + "time(7)", + [time(12, 0, 5, 123456), None, time(23, 59, 59, 123456), time(0, 0, 0, 0)], + ), ( pa.timestamp("us"), "datetime2(0)", @@ -187,14 +192,6 @@ def _test_arrow_test_data(cursor: mssql_python.Cursor, arrow_test_data, fetch_le # Validate that Parquet serialization/deserialization does not detect any issues tbl = pa.Table.from_batches([ret]) - # for some reason parquet converts seconds to milliseconds in time32 - for i_col, col in enumerate(tbl.columns): - if col.type == pa.time32("s"): - tbl = tbl.set_column( - i_col, - tbl.schema.field(i_col).name, - col.cast(pa.time32("ms")), - ) buffer = io.BytesIO() pq.write_table(tbl, buffer) buffer.seek(0)