Skip to content

Commit 311e8c7

Browse files
authored
Fix make_array null handling, update tests (#6900)
* Fix `make_array` null handling, update tests * Apply suggestions from code review
1 parent 4e2a72f commit 311e8c7

2 files changed

Lines changed: 136 additions & 33 deletions

File tree

datafusion/core/tests/sqllogictests/test_files/array.slt

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,18 @@ CREATE TABLE values(
2929
b INT,
3030
c INT,
3131
d FLOAT,
32-
e VARCHAR
32+
e VARCHAR,
33+
f VARCHAR
3334
) AS VALUES
34-
(1, 1, 2, 1.1, 'Lorem'),
35-
(2, 3, 4, 2.2, 'ipsum'),
36-
(3, 5, 6, 3.3, 'dolor'),
37-
(4, 7, 8, 4.4, 'sit'),
38-
(NULL, 9, 10, 5.5, 'amet'),
39-
(5, NULL, 12, 6.6, ','),
40-
(6, 11, NULL, 7.7, 'consectetur'),
41-
(7, 13, 14, NULL, 'adipiscing'),
42-
(8, 15, 16, 8.8, NULL)
35+
(1, 1, 2, 1.1, 'Lorem', 'A'),
36+
(2, 3, 4, 2.2, 'ipsum', ''),
37+
(3, 5, 6, 3.3, 'dolor', 'BB'),
38+
(4, 7, 8, 4.4, 'sit', NULL),
39+
(NULL, 9, 10, 5.5, 'amet', 'CCC'),
40+
(5, NULL, 12, 6.6, ',', 'DD'),
41+
(6, 11, NULL, 7.7, 'consectetur', 'E'),
42+
(7, 13, 14, NULL, 'adipiscing', 'F'),
43+
(8, 15, 16, 8.8, NULL, '')
4344
;
4445

4546
statement ok
@@ -189,34 +190,67 @@ select make_array(NULL), make_array(NULL, NULL, NULL), make_array(make_array(NUL
189190
----
190191
[] [] [[], []]
191192

192-
# make_array with columns #1
193-
query ????
194-
select make_array(a), make_array(b, c), make_array(d), make_array(e) from values;
195-
----
196-
[1] [1, 2] [1.1] [Lorem]
197-
[2] [3, 4] [2.2] [ipsum]
198-
[3] [5, 6] [3.3] [dolor]
199-
[4] [7, 8] [4.4] [sit]
200-
[0] [9, 10] [5.5] [amet]
201-
[5] [0, 12] [6.6] [,]
202-
[6] [11, 0] [7.7] [consectetur]
203-
[7] [13, 14] [0.0] [adipiscing]
204-
[8] [15, 16] [8.8] []
205-
206-
# make_array with columns #2
193+
# make_array with 1 columns
194+
query ???
195+
select make_array(a), make_array(d), make_array(e) from values;
196+
----
197+
[1] [1.1] [Lorem]
198+
[2] [2.2] [ipsum]
199+
[3] [3.3] [dolor]
200+
[4] [4.4] [sit]
201+
[] [5.5] [amet]
202+
[5] [6.6] [,]
203+
[6] [7.7] [consectetur]
204+
[7] [] [adipiscing]
205+
[8] [8.8] []
206+
207+
# make_array with 2 columns #1
208+
query ??
209+
select make_array(b, c), make_array(e, f) from values;
210+
----
211+
[1, 2] [Lorem, A]
212+
[3, 4] [ipsum, ]
213+
[5, 6] [dolor, BB]
214+
[7, 8] [sit, ]
215+
[9, 10] [amet, CCC]
216+
[, 12] [,, DD]
217+
[11, ] [consectetur, E]
218+
[13, 14] [adipiscing, F]
219+
[15, 16] [, ]
220+
221+
# make_array with 4 columns
207222
query ?
208223
select make_array(a, b, c, d) from values;
209224
----
210225
[1.0, 1.0, 2.0, 1.1]
211226
[2.0, 3.0, 4.0, 2.2]
212227
[3.0, 5.0, 6.0, 3.3]
213228
[4.0, 7.0, 8.0, 4.4]
214-
[0.0, 9.0, 10.0, 5.5]
215-
[5.0, 0.0, 12.0, 6.6]
216-
[6.0, 11.0, 0.0, 7.7]
217-
[7.0, 13.0, 14.0, 0.0]
229+
[, 9.0, 10.0, 5.5]
230+
[5.0, , 12.0, 6.6]
231+
[6.0, 11.0, , 7.7]
232+
[7.0, 13.0, 14.0, ]
218233
[8.0, 15.0, 16.0, 8.8]
219234

235+
# make_array null handling
236+
query ?B?BB
237+
select
238+
make_array(a), make_array(a)[1] IS NULL,
239+
make_array(e, f), make_array(e, f)[1] IS NULL, make_array(e, f)[2] IS NULL
240+
from values;
241+
----
242+
[1] false [Lorem, A] false false
243+
[2] false [ipsum, ] false false
244+
[3] false [dolor, BB] false false
245+
[4] false [sit, ] false true
246+
[] true [amet, CCC] false false
247+
[5] false [,, DD] false false
248+
[6] false [consectetur, E] false false
249+
[7] false [adipiscing, F] false false
250+
[8] false [, ] true false
251+
252+
253+
220254
## array_append
221255

222256
# array_append scalar function #2

datafusion/physical-expr/src/array_expressions.rs

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ macro_rules! downcast_arg {
4040
}};
4141
}
4242

43+
/// Downcasts multiple arguments into a single concrete type
44+
/// $ARGS: &[ArrayRef]
45+
/// $ARRAY_TYPE: type to downcast to
46+
///
47+
/// $returns a Vec<$ARRAY_TYPE>
4348
macro_rules! downcast_vec {
4449
($ARGS:expr, $ARRAY_TYPE:ident) => {{
4550
$ARGS
@@ -66,18 +71,38 @@ macro_rules! new_builder {
6671
}};
6772
}
6873

74+
/// Combines multiple arrays into a single ListArray
75+
///
76+
/// $ARGS: slice of arrays, each with $ARRAY_TYPE
77+
/// $ARRAY_TYPE: the type of the list elements
78+
/// $BUILDER_TYPE: the type of ArrayBuilder for the list elements
79+
///
80+
/// Returns: a ListArray where the elements each have the same type as
81+
/// $ARRAY_TYPE and each element have a length of $ARGS.len()
6982
macro_rules! array {
7083
($ARGS:expr, $ARRAY_TYPE:ident, $BUILDER_TYPE:ident) => {{
7184
let builder = new_builder!($BUILDER_TYPE, $ARGS[0].len());
7285
let mut builder =
7386
ListBuilder::<$BUILDER_TYPE>::with_capacity(builder, $ARGS.len());
7487

88+
let num_rows = $ARGS[0].len();
89+
assert!(
90+
$ARGS.iter().all(|a| a.len() == num_rows),
91+
"all arguments must have the same number of rows"
92+
);
93+
7594
// for each entry in the array
76-
for index in 0..$ARGS[0].len() {
95+
for index in 0..num_rows {
96+
// for each column
7797
for arg in $ARGS {
7898
match arg.as_any().downcast_ref::<$ARRAY_TYPE>() {
99+
// Copy the source array value into the target ListArray
79100
Some(arr) => {
80-
builder.values().append_value(arr.value(index));
101+
if arr.is_valid(index) {
102+
builder.values().append_value(arr.value(index));
103+
} else {
104+
builder.values().append_null();
105+
}
81106
}
82107
None => match arg.as_any().downcast_ref::<NullArray>() {
83108
Some(arr) => {
@@ -179,6 +204,46 @@ fn compute_array_dims(arr: Option<ArrayRef>) -> Result<Option<Vec<Option<u64>>>>
179204
}
180205
}
181206

207+
/// Convert one or more [`ArrayRef`] of the same type into a
208+
/// `ListArray`
209+
///
210+
/// # Example (non nested)
211+
///
212+
/// Calling `array(col1, col2)` where col1 and col2 are non nested
213+
/// would return a single new `ListArray`, where each row was a list
214+
/// of 2 elements:
215+
///
216+
/// ```text
217+
/// ┌─────────┐ ┌─────────┐ ┌──────────────┐
218+
/// │ ┌─────┐ │ │ ┌─────┐ │ │ ┌──────────┐ │
219+
/// │ │ A │ │ │ │ X │ │ │ │ [A, X] │ │
220+
/// │ ├─────┤ │ │ ├─────┤ │ │ ├──────────┤ │
221+
/// │ │NULL │ │ │ │ Y │ │──────────▶│ │[NULL, Y] │ │
222+
/// │ ├─────┤ │ │ ├─────┤ │ │ ├──────────┤ │
223+
/// │ │ C │ │ │ │ Z │ │ │ │ [C, Z] │ │
224+
/// │ └─────┘ │ │ └─────┘ │ │ └──────────┘ │
225+
/// └─────────┘ └─────────┘ └──────────────┘
226+
/// col1 col2 output
227+
/// ```
228+
///
229+
/// # Example (nested)
230+
///
231+
/// Calling `array(col1, col2)` where col1 and col2 are lists
232+
/// would return a single new `ListArray`, where each row was a list
233+
/// of the corresponding elements of col1 and col2 flattened.
234+
///
235+
/// ``` text
236+
/// ┌──────────────┐ ┌──────────────┐ ┌────────────────────────┐
237+
/// │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌────────────────────┐ │
238+
/// │ │ [A, X] │ │ │ │ [] │ │ │ │ [A, X] │ │
239+
/// │ ├──────────┤ │ │ ├──────────┤ │ │ ├────────────────────┤ │
240+
/// │ │[NULL, Y] │ │ │ │[Q, R, S] │ │───────▶│ │ [NULL, Y, Q, R, S] │ │
241+
/// │ ├──────────┤ │ │ ├──────────┤ │ │ ├────────────────────┤ │
242+
/// │ │ [C, Z] │ │ │ │ NULL │ │ │ │ [C, Z, NULL] │ │
243+
/// │ └──────────┘ │ │ └──────────┘ │ │ └────────────────────┘ │
244+
/// └──────────────┘ └──────────────┘ └────────────────────────┘
245+
/// col1 col2 output
246+
/// ```
182247
fn array_array(args: &[ArrayRef], data_type: DataType) -> Result<ArrayRef> {
183248
// do not accept 0 arguments.
184249
if args.is_empty() {
@@ -200,6 +265,7 @@ fn array_array(args: &[ArrayRef], data_type: DataType) -> Result<ArrayRef> {
200265
let mut mutable =
201266
MutableArrayData::with_capacities(array_data, false, capacity);
202267

268+
// Copy over all the child data
203269
for (i, a) in arrays.iter().enumerate() {
204270
mutable.extend(i, 0, a.len())
205271
}
@@ -239,8 +305,11 @@ fn array_array(args: &[ArrayRef], data_type: DataType) -> Result<ArrayRef> {
239305
Ok(res)
240306
}
241307

242-
/// put values in an array.
243-
pub fn array(values: &[ColumnarValue]) -> Result<ColumnarValue> {
308+
/// Convert one or more [`ColumnarValue`] of the same type into a
309+
/// `ListArray`
310+
///
311+
/// See [`array_array`] for more details.
312+
fn array(values: &[ColumnarValue]) -> Result<ColumnarValue> {
244313
let arrays: Vec<ArrayRef> = values
245314
.iter()
246315
.map(|x| match x {

0 commit comments

Comments
 (0)