Skip to content

Commit 0b75443

Browse files
Fixed bug when fetching multiple consecutive null values into a data
frame.
1 parent 9ff772c commit 0b75443

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed

doc/src/release_notes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Thin Mode Changes
3838
maintenance not being sent when using connection pools with asyncio.
3939
#) Fixed bug resulting in ``TypeError`` when using
4040
:attr:`DeqOptions.correlation` for buffered delivery mode.
41+
#) Fixed bug when fetching multiple consecutive null values into a data frame.
4142

4243
Thick Mode Changes
4344
++++++++++++++++++

src/oracledb/interchange/nanoarrow_bridge.pyx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ cdef extern from "nanoarrow/nanoarrow.c":
5555
ArrowBufferViewData data
5656
int64_t size_bytes
5757

58+
cdef struct ArrowBitmap:
59+
ArrowBuffer buffer
60+
5861
cdef struct ArrowArrayView:
5962
ArrowBufferView *buffer_views
6063

@@ -88,6 +91,7 @@ cdef extern from "nanoarrow/nanoarrow.c":
8891
ArrowErrorCode ArrowArrayReserve(ArrowArray* array,
8992
int64_t additional_size_elements)
9093
ArrowErrorCode ArrowArrayStartAppending(ArrowArray* array)
94+
ArrowBitmap* ArrowArrayValidityBitmap(ArrowArray* array)
9195
ArrowErrorCode ArrowArrayViewInitFromArray(ArrowArrayView* array_view,
9296
ArrowArray* array)
9397
int8_t ArrowBitGet(const uint8_t* bits, int64_t i)
@@ -335,8 +339,15 @@ cdef class OracleArrowArray:
335339
int64_t index
336340
uint8_t *ptr
337341
void* temp
342+
ArrowBitmap *bitamp
338343
if array is None:
339344
array = self
345+
bitmap = ArrowArrayValidityBitmap(array.arrow_array)
346+
if bitmap != NULL and bitmap.buffer.data != NULL:
347+
as_bool = ArrowBitGet(bitmap.buffer.data, index)
348+
if not as_bool:
349+
self.append_null()
350+
return 0
340351
index = array.arrow_array.length - 1
341352
if array.arrow_type in (NANOARROW_TYPE_INT64, NANOARROW_TYPE_TIMESTAMP):
342353
data_buffer = ArrowArrayBuffer(array.arrow_array, 1)

tests/test_8000_dataframe.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,45 @@ def test_8026(self):
633633
fetched_data = self.__get_data_from_df(fetched_df)
634634
self.assertEqual(fetched_data, data)
635635

636+
def test_8027(self):
637+
"8027 - fetch data with multiple rows containing null values"
638+
self.__check_interop()
639+
ora_df = self.conn.fetch_df_all(
640+
"""
641+
select to_date(null) as data from dual
642+
union all
643+
select to_date(null) as data from dual
644+
union all
645+
select to_date(null) as data from dual
646+
union all
647+
select to_date('2025-06-11', 'YYYY-MM-DD') as data from dual
648+
union all
649+
select to_date(null) as data from dual
650+
union all
651+
select to_date(null) as data from dual
652+
union all
653+
select to_date(null) as data from dual
654+
union all
655+
select to_date(null) as data from dual
656+
"""
657+
)
658+
data = [
659+
(None,),
660+
(None,),
661+
(None,),
662+
(datetime.datetime(2025, 6, 11),),
663+
(None,),
664+
(None,),
665+
(None,),
666+
(None,),
667+
]
668+
fetched_tab = pyarrow.Table.from_arrays(
669+
ora_df.column_arrays(), names=ora_df.column_names()
670+
)
671+
fetched_df = fetched_tab.to_pandas()
672+
fetched_data = self.__get_data_from_df(fetched_df)
673+
self.assertEqual(fetched_data, data)
674+
636675

637676
if __name__ == "__main__":
638677
test_env.run_test_cases()

tests/test_8100_dataframe_async.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,45 @@ async def test_8122(self):
586586
fetched_data = self.__get_data_from_df(fetched_df)
587587
self.assertEqual(fetched_data, data)
588588

589+
async def test_8123(self):
590+
"8123 - fetch data with multiple rows containing null values"
591+
self.__check_interop()
592+
ora_df = await self.conn.fetch_df_all(
593+
"""
594+
select to_date(null) as data from dual
595+
union all
596+
select to_date(null) as data from dual
597+
union all
598+
select to_date(null) as data from dual
599+
union all
600+
select to_date('2025-06-11', 'YYYY-MM-DD') as data from dual
601+
union all
602+
select to_date(null) as data from dual
603+
union all
604+
select to_date(null) as data from dual
605+
union all
606+
select to_date(null) as data from dual
607+
union all
608+
select to_date(null) as data from dual
609+
"""
610+
)
611+
data = [
612+
(None,),
613+
(None,),
614+
(None,),
615+
(datetime.datetime(2025, 6, 11),),
616+
(None,),
617+
(None,),
618+
(None,),
619+
(None,),
620+
]
621+
fetched_tab = pyarrow.Table.from_arrays(
622+
ora_df.column_arrays(), names=ora_df.column_names()
623+
)
624+
fetched_df = fetched_tab.to_pandas()
625+
fetched_data = self.__get_data_from_df(fetched_df)
626+
self.assertEqual(fetched_data, data)
627+
589628

590629
if __name__ == "__main__":
591630
test_env.run_test_cases()

0 commit comments

Comments
 (0)