Skip to content

Commit 3d91302

Browse files
authored
support duration in ffi (#1689)
1 parent b9a41f3 commit 3d91302

File tree

3 files changed

+54
-5
lines changed

3 files changed

+54
-5
lines changed

arrow-pyarrow-integration-testing/tests/test_sql.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ def assert_pyarrow_leak():
5555
pa.timestamp("us"),
5656
pa.timestamp("us", tz="UTC"),
5757
pa.timestamp("us", tz="Europe/Paris"),
58+
pa.duration("s"),
59+
pa.duration("ms"),
60+
pa.duration("us"),
61+
pa.duration("ns"),
5862
pa.float16(),
5963
pa.float32(),
6064
pa.float64(),
@@ -86,7 +90,6 @@ def assert_pyarrow_leak():
8690

8791
_unsupported_pyarrow_types = [
8892
pa.decimal256(76, 38),
89-
pa.duration("s"),
9093
pa.map_(pa.string(), pa.int32()),
9194
pa.union(
9295
[pa.field("a", pa.binary(10)), pa.field("b", pa.string())],

arrow/src/datatypes/ffi.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ impl TryFrom<&FFI_ArrowSchema> for DataType {
5252
"ttm" => DataType::Time32(TimeUnit::Millisecond),
5353
"ttu" => DataType::Time64(TimeUnit::Microsecond),
5454
"ttn" => DataType::Time64(TimeUnit::Nanosecond),
55+
"tDs" => DataType::Duration(TimeUnit::Second),
56+
"tDm" => DataType::Duration(TimeUnit::Millisecond),
57+
"tDu" => DataType::Duration(TimeUnit::Microsecond),
58+
"tDn" => DataType::Duration(TimeUnit::Nanosecond),
5559
"+l" => {
5660
let c_child = c_schema.child(0);
5761
DataType::List(Box::new(Field::try_from(c_child)?))
@@ -251,6 +255,10 @@ fn get_format_string(dtype: &DataType) -> Result<String> {
251255
DataType::Timestamp(TimeUnit::Millisecond, Some(tz)) => Ok(format!("tsm:{}", tz)),
252256
DataType::Timestamp(TimeUnit::Microsecond, Some(tz)) => Ok(format!("tsu:{}", tz)),
253257
DataType::Timestamp(TimeUnit::Nanosecond, Some(tz)) => Ok(format!("tsn:{}", tz)),
258+
DataType::Duration(TimeUnit::Second) => Ok("tDs".to_string()),
259+
DataType::Duration(TimeUnit::Millisecond) => Ok("tDm".to_string()),
260+
DataType::Duration(TimeUnit::Microsecond) => Ok("tDu".to_string()),
261+
DataType::Duration(TimeUnit::Nanosecond) => Ok("tDn".to_string()),
254262
DataType::List(_) => Ok("+l".to_string()),
255263
DataType::LargeList(_) => Ok("+L".to_string()),
256264
DataType::Struct(_) => Ok("+s".to_string()),

arrow/src/ffi.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ fn bit_width(data_type: &DataType, i: usize) -> Result<usize> {
314314
(DataType::Float64, 1) => size_of::<f64>() * 8,
315315
(DataType::Decimal(..), 1) => size_of::<i128>() * 8,
316316
(DataType::Timestamp(..), 1) => size_of::<i64>() * 8,
317+
(DataType::Duration(..), 1) => size_of::<i64>() * 8,
317318
// primitive types have a single buffer
318319
(DataType::Boolean, _) |
319320
(DataType::UInt8, _) |
@@ -327,7 +328,8 @@ fn bit_width(data_type: &DataType, i: usize) -> Result<usize> {
327328
(DataType::Float32, _) |
328329
(DataType::Float64, _) |
329330
(DataType::Decimal(..), _) |
330-
(DataType::Timestamp(..), _) => {
331+
(DataType::Timestamp(..), _) |
332+
(DataType::Duration(..), _) => {
331333
return Err(ArrowError::CDataInterface(format!(
332334
"The datatype \"{:?}\" expects 2 buffers, but requested {}. Please verify that the C data interface is correctly implemented.",
333335
data_type, i
@@ -873,9 +875,9 @@ mod tests {
873875
use super::*;
874876
use crate::array::{
875877
export_array_into_raw, make_array, Array, ArrayData, BooleanArray, DecimalArray,
876-
DictionaryArray, FixedSizeBinaryArray, FixedSizeListArray, GenericBinaryArray,
877-
GenericListArray, GenericStringArray, Int32Array, OffsetSizeTrait,
878-
Time32MillisecondArray, TimestampMillisecondArray,
878+
DictionaryArray, DurationSecondArray, FixedSizeBinaryArray, FixedSizeListArray,
879+
GenericBinaryArray, GenericListArray, GenericStringArray, Int32Array,
880+
OffsetSizeTrait, Time32MillisecondArray, TimestampMillisecondArray,
879881
};
880882
use crate::compute::kernels;
881883
use crate::datatypes::{Field, Int8Type};
@@ -1358,4 +1360,40 @@ mod tests {
13581360
}
13591361
Ok(())
13601362
}
1363+
1364+
#[test]
1365+
fn test_duration() -> Result<()> {
1366+
// create an array natively
1367+
let array = DurationSecondArray::from(vec![None, Some(1), Some(2)]);
1368+
1369+
// export it
1370+
let array = ArrowArray::try_from(array.data().clone())?;
1371+
1372+
// (simulate consumer) import it
1373+
let data = ArrayData::try_from(array)?;
1374+
let array = make_array(data);
1375+
1376+
// perform some operation
1377+
let array = kernels::concat::concat(&[array.as_ref(), array.as_ref()]).unwrap();
1378+
let array = array
1379+
.as_any()
1380+
.downcast_ref::<DurationSecondArray>()
1381+
.unwrap();
1382+
1383+
// verify
1384+
assert_eq!(
1385+
array,
1386+
&DurationSecondArray::from(vec![
1387+
None,
1388+
Some(1),
1389+
Some(2),
1390+
None,
1391+
Some(1),
1392+
Some(2)
1393+
])
1394+
);
1395+
1396+
// (drop/release)
1397+
Ok(())
1398+
}
13611399
}

0 commit comments

Comments
 (0)