Skip to content

Commit 4ffec1c

Browse files
committed
Support concatenation of mixed FixedSizeBinary types without conversion to Binary
1 parent b0fe223 commit 4ffec1c

1 file changed

Lines changed: 57 additions & 44 deletions

File tree

  • datafusion/expr-common/src/type_coercion

datafusion/expr-common/src/type_coercion/binary.rs

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ impl<'a> BinaryTypeCoercer<'a> {
237237
})
238238
}
239239
StringConcat => {
240-
string_concat_coercion(lhs, rhs).map(Signature::uniform).ok_or_else(|| {
240+
string_concat_coercion(lhs, rhs).ok_or_else(|| {
241241
plan_datafusion_err!(
242242
"Cannot infer common string type for string concat operation {} {} {}", self.lhs, self.op, self.rhs
243243
)
@@ -1635,50 +1635,63 @@ fn ree_coercion(
16351635
/// 1. At least one side of lhs and rhs should be string type (Utf8 / LargeUtf8)
16361636
/// 2. Data type of the other side should be able to cast to string type
16371637
/// 3. Binary and string types cannot be mixed
1638-
fn string_concat_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType> {
1638+
fn string_concat_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<Signature> {
16391639
use arrow::datatypes::DataType::*;
1640-
string_coercion(lhs_type, rhs_type).or_else(|| match (lhs_type, rhs_type) {
1641-
// Allow pure binary + binary
1642-
(
1643-
Binary | LargeBinary | BinaryView | FixedSizeBinary(_),
1644-
Binary | LargeBinary | BinaryView | FixedSizeBinary(_),
1645-
) => {
1646-
// Coerce fixed-sized binary to variable-sized `Binary` to make uniform signature
1647-
// with the `Binary` result
1648-
let lhs_type = match lhs_type {
1649-
FixedSizeBinary(_) => &Binary,
1650-
val => val,
1651-
};
1652-
let rhs_type = match rhs_type {
1653-
FixedSizeBinary(_) => &Binary,
1654-
val => val,
1655-
};
1656-
binary_coercion(lhs_type, rhs_type)
1657-
}
1658-
// Deny other mixed binary + string combinations
1659-
(
1660-
Binary | LargeBinary | BinaryView | FixedSizeBinary(_),
1661-
Utf8 | LargeUtf8 | Utf8View,
1662-
) => None,
1663-
(
1664-
Utf8 | LargeUtf8 | Utf8View,
1665-
Binary | LargeBinary | BinaryView | FixedSizeBinary(_),
1666-
) => None,
1667-
// Predicate-based coercion rules are following
1668-
(Utf8View, from_type) | (from_type, Utf8View) => {
1669-
string_concat_internal_coercion(from_type, &Utf8View)
1670-
}
1671-
(Utf8, from_type) | (from_type, Utf8) => {
1672-
string_concat_internal_coercion(from_type, &Utf8)
1673-
}
1674-
(LargeUtf8, from_type) | (from_type, LargeUtf8) => {
1675-
string_concat_internal_coercion(from_type, &LargeUtf8)
1676-
}
1677-
(Dictionary(_, lhs_value_type), Dictionary(_, rhs_value_type)) => {
1678-
string_coercion(lhs_value_type, rhs_value_type).or(None)
1679-
}
1680-
_ => None,
1681-
})
1640+
1641+
string_coercion(lhs_type, rhs_type)
1642+
.map(Signature::uniform)
1643+
.or_else(|| match (lhs_type, rhs_type) {
1644+
// Allow concatenation of mixed fixed size binary
1645+
(FixedSizeBinary(l), FixedSizeBinary(r)) => Some(Signature {
1646+
lhs: lhs_type.clone(),
1647+
rhs: rhs_type.clone(),
1648+
ret: FixedSizeBinary(l + r),
1649+
}),
1650+
// Allow pure binary + binary
1651+
(
1652+
Binary | LargeBinary | BinaryView | FixedSizeBinary(_),
1653+
Binary | LargeBinary | BinaryView | FixedSizeBinary(_),
1654+
) => {
1655+
// Coerce fixed-sized binary to variable-sized `Binary` to make uniform signature
1656+
// with the `Binary` result
1657+
let lhs_type = match lhs_type {
1658+
FixedSizeBinary(_) => &Binary,
1659+
val => val,
1660+
};
1661+
let rhs_type = match rhs_type {
1662+
FixedSizeBinary(_) => &Binary,
1663+
val => val,
1664+
};
1665+
binary_coercion(lhs_type, rhs_type).map(Signature::uniform)
1666+
}
1667+
// Deny other mixed binary + string combinations
1668+
(
1669+
Binary | LargeBinary | BinaryView | FixedSizeBinary(_),
1670+
Utf8 | LargeUtf8 | Utf8View,
1671+
) => None,
1672+
(
1673+
Utf8 | LargeUtf8 | Utf8View,
1674+
Binary | LargeBinary | BinaryView | FixedSizeBinary(_),
1675+
) => None,
1676+
// Predicate-based coercion rules are following
1677+
(Utf8View, from_type) | (from_type, Utf8View) => {
1678+
string_concat_internal_coercion(from_type, &Utf8View)
1679+
.map(Signature::uniform)
1680+
}
1681+
(Utf8, from_type) | (from_type, Utf8) => {
1682+
string_concat_internal_coercion(from_type, &Utf8).map(Signature::uniform)
1683+
}
1684+
(LargeUtf8, from_type) | (from_type, LargeUtf8) => {
1685+
string_concat_internal_coercion(from_type, &LargeUtf8)
1686+
.map(Signature::uniform)
1687+
}
1688+
(Dictionary(_, lhs_value_type), Dictionary(_, rhs_value_type)) => {
1689+
string_coercion(lhs_value_type, rhs_value_type)
1690+
.or(None)
1691+
.map(Signature::uniform)
1692+
}
1693+
_ => None,
1694+
})
16821695
}
16831696

16841697
fn array_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType> {

0 commit comments

Comments
 (0)