From 9ead7c4810b4bdeae7442177b8900d38c58ca4b4 Mon Sep 17 00:00:00 2001 From: Sean Smith Date: Thu, 19 Dec 2024 09:27:31 -0600 Subject: [PATCH 1/2] list_to_string --- .../scalar/{list.rs => list/binary.rs} | 32 +-- .../src/executor/scalar/list/mod.rs | 34 +++ .../src/executor/scalar/list/unary.rs | 160 ++++++++++++++ .../functions/scalar/builtin/comparison.rs | 170 +++++++-------- .../scalar/builtin/list/list_to_string.rs | 195 ++++++++++++++++++ .../src/functions/scalar/builtin/list/mod.rs | 3 + .../src/functions/scalar/builtin/mod.rs | 1 + .../scalar/builtin/similarity/l2_distance.rs | 6 +- .../scalars/{ => list}/list_extract.slt | 0 .../functions/scalars/list/list_to_string.slt | 12 ++ .../scalars/{ => list}/list_values.slt | 0 11 files changed, 502 insertions(+), 111 deletions(-) rename crates/rayexec_bullet/src/executor/scalar/{list.rs => list/binary.rs} (86%) create mode 100644 crates/rayexec_bullet/src/executor/scalar/list/mod.rs create mode 100644 crates/rayexec_bullet/src/executor/scalar/list/unary.rs create mode 100644 crates/rayexec_execution/src/functions/scalar/builtin/list/list_to_string.rs rename slt/standard/functions/scalars/{ => list}/list_extract.slt (100%) create mode 100644 slt/standard/functions/scalars/list/list_to_string.slt rename slt/standard/functions/scalars/{ => list}/list_values.slt (100%) diff --git a/crates/rayexec_bullet/src/executor/scalar/list.rs b/crates/rayexec_bullet/src/executor/scalar/list/binary.rs similarity index 86% rename from crates/rayexec_bullet/src/executor/scalar/list.rs rename to crates/rayexec_bullet/src/executor/scalar/list/binary.rs index 70622af65..a5f9c0100 100644 --- a/crates/rayexec_bullet/src/executor/scalar/list.rs +++ b/crates/rayexec_bullet/src/executor/scalar/list/binary.rs @@ -1,5 +1,6 @@ use rayexec_error::{not_implemented, RayexecError, Result}; +use super::{get_inner_array_selection, get_inner_array_storage}; use crate::array::{Array, ArrayData}; use crate::bitmap::Bitmap; use crate::executor::builder::{ArrayBuilder, ArrayDataBuffer}; @@ -14,9 +15,11 @@ pub trait BinaryListReducer { fn finish(self) -> O; } +// TODO: Cleanup + /// List executor that allows for different list lengths, and nulls inside of /// lists. -pub type FlexibleListExecutor = ListExecutor; +pub type FlexibleBinaryListExecutor = BinaryListExecutor; /// Execute reductions on lists. /// @@ -25,10 +28,10 @@ pub type FlexibleListExecutor = ListExecutor; /// /// `ALLOW_NULLS` controls if this allows nulls in lists. #[derive(Debug, Clone, Copy)] -pub struct ListExecutor; +pub struct BinaryListExecutor; impl - ListExecutor + BinaryListExecutor { /// Execute a reducer on two list arrays. pub fn binary_reduce<'a, S, B, R>( @@ -161,26 +164,3 @@ impl } } } - -/// Gets the inner array storage. Checks to ensure the inner array does not -/// contain NULLs. -fn get_inner_array_storage(array: &Array) -> Result<(S::Storage<'_>, Option<&Bitmap>)> -where - S: PhysicalStorage, -{ - match array.array_data() { - ArrayData::List(d) => { - let storage = S::get_storage(d.array.array_data())?; - let validity = d.array.validity(); - Ok((storage, validity)) - } - _ => Err(RayexecError::new("Expected list array data")), - } -} - -fn get_inner_array_selection(array: &Array) -> Result> { - match array.array_data() { - ArrayData::List(d) => Ok(d.array.selection_vector()), - _ => Err(RayexecError::new("Expected list array data")), - } -} diff --git a/crates/rayexec_bullet/src/executor/scalar/list/mod.rs b/crates/rayexec_bullet/src/executor/scalar/list/mod.rs new file mode 100644 index 000000000..86dc41b98 --- /dev/null +++ b/crates/rayexec_bullet/src/executor/scalar/list/mod.rs @@ -0,0 +1,34 @@ +mod binary; +pub use binary::*; + +mod unary; +use rayexec_error::{RayexecError, Result}; +pub use unary::*; + +use crate::array::{Array, ArrayData}; +use crate::bitmap::Bitmap; +use crate::executor::physical_type::PhysicalStorage; +use crate::selection::SelectionVector; + +/// Gets the inner array storage. Checks to ensure the inner array does not +/// contain NULLs. +fn get_inner_array_storage(array: &Array) -> Result<(S::Storage<'_>, Option<&Bitmap>)> +where + S: PhysicalStorage, +{ + match array.array_data() { + ArrayData::List(d) => { + let storage = S::get_storage(d.array.array_data())?; + let validity = d.array.validity(); + Ok((storage, validity)) + } + _ => Err(RayexecError::new("Expected list array data")), + } +} + +fn get_inner_array_selection(array: &Array) -> Result> { + match array.array_data() { + ArrayData::List(d) => Ok(d.array.selection_vector()), + _ => Err(RayexecError::new("Expected list array data")), + } +} diff --git a/crates/rayexec_bullet/src/executor/scalar/list/unary.rs b/crates/rayexec_bullet/src/executor/scalar/list/unary.rs new file mode 100644 index 000000000..9483be635 --- /dev/null +++ b/crates/rayexec_bullet/src/executor/scalar/list/unary.rs @@ -0,0 +1,160 @@ +use rayexec_error::Result; + +use crate::array::Array; +use crate::executor::physical_type::{PhysicalList, PhysicalStorage}; +use crate::executor::scalar::list::{get_inner_array_selection, get_inner_array_storage}; +use crate::selection; +use crate::storage::AddressableStorage; + +#[derive(Debug)] +pub struct ListEntry { + /// Index of the entry within the list. + pub inner_idx: i32, + /// Then entry, None if not valid + pub entry: Option, +} + +#[derive(Debug, Clone, Copy)] +pub struct UnaryListExecutor; + +impl UnaryListExecutor { + pub fn for_each<'a, S, Op>(array: &'a Array, mut op: Op) -> Result<()> + where + Op: FnMut(usize, Option>>), + S: PhysicalStorage, + { + let selection = array.selection_vector(); + let metadata = PhysicalList::get_storage(array.array_data())?; + + let (values, inner_validity) = get_inner_array_storage::(array)?; + let inner_sel = get_inner_array_selection(array)?; + + match (array.validity(), inner_validity) { + (None, None) => { + // No validities for parent array or child array. + + println!("LEN: {}", array.logical_len()); + + for row_idx in 0..array.logical_len() { + let sel = unsafe { selection::get_unchecked(selection, row_idx) }; + let m = unsafe { metadata.get_unchecked(sel) }; + + for inner_idx in 0..m.len { + let sel = + unsafe { selection::get_unchecked(inner_sel, inner_idx as usize) }; + let v = unsafe { values.get_unchecked(sel) }; + + op( + row_idx, + Some(ListEntry { + inner_idx, + entry: Some(v), + }), + ); + } + } + } + (Some(outer_validity), None) => { + // Outer validity, no child validity. + for row_idx in 0..array.logical_len() { + let sel = unsafe { selection::get_unchecked(selection, row_idx) }; + + if !outer_validity.value(row_idx) { + op(row_idx, None); + continue; + } + + let m = unsafe { metadata.get_unchecked(sel) }; + + for inner_idx in 0..m.len { + let sel = + unsafe { selection::get_unchecked(inner_sel, inner_idx as usize) }; + let v = unsafe { values.get_unchecked(sel) }; + + op( + row_idx, + Some(ListEntry { + inner_idx, + entry: Some(v), + }), + ); + } + } + } + (None, Some(inner_validity)) => { + // Outer all valid, inner contains validities. + for row_idx in 0..array.logical_len() { + let sel = unsafe { selection::get_unchecked(selection, row_idx) }; + let m = unsafe { metadata.get_unchecked(sel) }; + + for inner_idx in 0..m.len { + let sel = + unsafe { selection::get_unchecked(inner_sel, inner_idx as usize) }; + + if !inner_validity.value(sel) { + op( + row_idx, + Some(ListEntry { + inner_idx, + entry: None, + }), + ); + continue; + } + + let v = unsafe { values.get_unchecked(sel) }; + + op( + row_idx, + Some(ListEntry { + inner_idx, + entry: Some(v), + }), + ); + } + } + } + (Some(outer_validity), Some(inner_validity)) => { + // Need to check everything. + for row_idx in 0..array.logical_len() { + let sel = unsafe { selection::get_unchecked(selection, row_idx) }; + + if !outer_validity.value(row_idx) { + op(row_idx, None); + continue; + } + + let m = unsafe { metadata.get_unchecked(sel) }; + + for inner_idx in 0..m.len { + let sel = + unsafe { selection::get_unchecked(inner_sel, inner_idx as usize) }; + + if !inner_validity.value(sel) { + op( + row_idx, + Some(ListEntry { + inner_idx, + entry: None, + }), + ); + continue; + } + + let v = unsafe { values.get_unchecked(sel) }; + + op( + row_idx, + Some(ListEntry { + inner_idx, + entry: Some(v), + }), + ); + } + } + } + } + + Ok(()) + } +} diff --git a/crates/rayexec_execution/src/functions/scalar/builtin/comparison.rs b/crates/rayexec_execution/src/functions/scalar/builtin/comparison.rs index 1c21405f8..57b6958c9 100644 --- a/crates/rayexec_execution/src/functions/scalar/builtin/comparison.rs +++ b/crates/rayexec_execution/src/functions/scalar/builtin/comparison.rs @@ -29,7 +29,11 @@ use rayexec_bullet::executor::physical_type::{ PhysicalUntypedNull, PhysicalUtf8, }; -use rayexec_bullet::executor::scalar::{BinaryExecutor, BinaryListReducer, FlexibleListExecutor}; +use rayexec_bullet::executor::scalar::{ + BinaryExecutor, + BinaryListReducer, + FlexibleBinaryListExecutor, +}; use rayexec_bullet::scalar::decimal::{Decimal128Type, Decimal64Type, DecimalType}; use rayexec_bullet::storage::PrimitiveStorage; use rayexec_error::{RayexecError, Result}; @@ -670,96 +674,96 @@ where }; let array = match self.inner_physical_type { - PhysicalType::UntypedNull => FlexibleListExecutor::binary_reduce::< + PhysicalType::UntypedNull => FlexibleBinaryListExecutor::binary_reduce::< PhysicalUntypedNull, _, ListComparisonReducer<_, O>, >(left, right, builder)?, - PhysicalType::Boolean => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Int8 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Int16 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Int32 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Int64 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Int128 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::UInt8 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::UInt16 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::UInt32 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::UInt64 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::UInt128 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Float16 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Float32 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Float64 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Interval => FlexibleListExecutor::binary_reduce::< + PhysicalType::Boolean => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalBool, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Int8 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalI8, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Int16 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalI16, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Int32 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalI32, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Int64 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalI64, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Int128 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalI128, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::UInt8 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalU8, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::UInt16 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalU16, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::UInt32 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalU32, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::UInt64 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalU64, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::UInt128 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalU128, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Float16 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalF16, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Float32 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalF32, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Float64 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalF64, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Interval => FlexibleBinaryListExecutor::binary_reduce::< PhysicalInterval, _, ListComparisonReducer<_, O>, >(left, right, builder)?, - PhysicalType::Binary => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } - PhysicalType::Utf8 => { - FlexibleListExecutor::binary_reduce::>( - left, right, builder, - )? - } + PhysicalType::Binary => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalBinary, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, + PhysicalType::Utf8 => FlexibleBinaryListExecutor::binary_reduce::< + PhysicalUtf8, + _, + ListComparisonReducer<_, O>, + >(left, right, builder)?, PhysicalType::List => { return Err(RayexecError::new( "Comparison between nested lists not yet supported", diff --git a/crates/rayexec_execution/src/functions/scalar/builtin/list/list_to_string.rs b/crates/rayexec_execution/src/functions/scalar/builtin/list/list_to_string.rs new file mode 100644 index 000000000..09b5fb162 --- /dev/null +++ b/crates/rayexec_execution/src/functions/scalar/builtin/list/list_to_string.rs @@ -0,0 +1,195 @@ +use std::fmt::{self, Write as _}; +use std::marker::PhantomData; + +use rayexec_bullet::array::Array; +use rayexec_bullet::bitmap::Bitmap; +use rayexec_bullet::datatype::{DataType, DataTypeId}; +use rayexec_bullet::executor::builder::{ArrayBuilder, ArrayDataBuffer, GermanVarlenBuffer}; +use rayexec_bullet::executor::physical_type::{ + PhysicalF16, + PhysicalF32, + PhysicalF64, + PhysicalI128, + PhysicalI16, + PhysicalI32, + PhysicalI64, + PhysicalI8, + PhysicalStorage, + PhysicalU16, + PhysicalU32, + PhysicalU64, + PhysicalU8, + PhysicalUtf8, +}; +use rayexec_bullet::executor::scalar::UnaryListExecutor; +use rayexec_error::{RayexecError, Result}; + +use crate::expr::Expression; +use crate::functions::documentation::{Category, Documentation, Example}; +use crate::functions::scalar::{PlannedScalarFunction, ScalarFunction, ScalarFunctionImpl}; +use crate::functions::{invalid_input_types_error, plan_check_num_args, FunctionInfo, Signature}; +use crate::logical::binder::table_list::TableList; +use crate::optimizer::expr_rewrite::const_fold::ConstFold; +use crate::optimizer::expr_rewrite::ExpressionRewriteRule; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ListToString; + +impl FunctionInfo for ListToString { + fn name(&self) -> &'static str { + "list_to_string" + } + + fn aliases(&self) -> &'static [&'static str] { + &["array_to_string"] + } + + fn signatures(&self) -> &[Signature] { + // TODO: Variant with null string. + &[Signature { + positional_args: &[DataTypeId::List, DataTypeId::Utf8], + variadic_arg: None, + return_type: DataTypeId::Utf8, + doc: Some(&Documentation { + category: Category::List, + description: "Convert each element to a string and concatenate with a delimiter.", + arguments: &["list", "delimiter"], + example: Some(Example { + example: "list_to_string([4, 5, 6], ',')", + output: "4,5,6", + }), + }), + }] + } +} + +impl ScalarFunction for ListToString { + fn plan( + &self, + table_list: &TableList, + inputs: Vec, + ) -> Result { + plan_check_num_args(self, &inputs, 2)?; + + let list_meta = match inputs[0].datatype(table_list)? { + DataType::List(m) => m, + other => return Err(invalid_input_types_error(self, &[other])), + }; + + // Requires constant sep for now. + let sep = ConstFold::rewrite(table_list, inputs[1].clone())? + .try_into_scalar()? + .try_into_string()?; + + let function_impl: Box = match list_meta.datatype.as_ref() { + DataType::Int8 => Box::new(ListToStringImpl::::new(sep)), + DataType::Int16 => Box::new(ListToStringImpl::::new(sep)), + DataType::Int32 => Box::new(ListToStringImpl::::new(sep)), + DataType::Int64 => Box::new(ListToStringImpl::::new(sep)), + DataType::Int128 => Box::new(ListToStringImpl::::new(sep)), + DataType::UInt8 => Box::new(ListToStringImpl::::new(sep)), + DataType::UInt16 => Box::new(ListToStringImpl::::new(sep)), + DataType::UInt32 => Box::new(ListToStringImpl::::new(sep)), + DataType::UInt64 => Box::new(ListToStringImpl::::new(sep)), + DataType::UInt128 => Box::new(ListToStringImpl::::new(sep)), + DataType::Float16 => Box::new(ListToStringImpl::::new(sep)), + DataType::Float32 => Box::new(ListToStringImpl::::new(sep)), + DataType::Float64 => Box::new(ListToStringImpl::::new(sep)), + DataType::Utf8 => Box::new(ListToStringImpl::::new(sep)), + + // TODO: Need special impls for decimals, dates, etc. that wrap the + // format logic. + other => { + return Err(RayexecError::new(format!( + "Cannot yet format lists containing {other} datatypes", + ))) + } + }; + + Ok(PlannedScalarFunction { + function: Box::new(*self), + return_type: DataType::Utf8, + inputs, + function_impl, + }) + } +} + +#[derive(Debug, Clone)] +pub struct ListToStringImpl { + sep: String, + _s: PhantomData, +} + +impl ListToStringImpl { + fn new(sep: String) -> Self { + ListToStringImpl { + sep, + _s: PhantomData, + } + } +} + +impl ScalarFunctionImpl for ListToStringImpl +where + S: PhysicalStorage, + for<'a> S::Type<'a>: fmt::Display + fmt::Debug, +{ + fn execute(&self, inputs: &[&Array]) -> Result { + let lists = inputs[0]; + list_to_string_inner::(lists, &self.sep) + } +} + +fn list_to_string_inner<'a, S>(lists: &'a Array, sep: &str) -> Result +where + S: PhysicalStorage, + S::Type<'a>: fmt::Display + fmt::Debug, +{ + let mut builder = ArrayBuilder { + datatype: DataType::Utf8, + buffer: GermanVarlenBuffer::with_len(lists.logical_len()), + }; + let mut validity = Bitmap::new_with_all_true(lists.logical_len()); + + let mut skip_sep = true; + let mut buf = String::new(); + + let mut curr_row = 0; + + UnaryListExecutor::for_each::(lists, |row, ent| { + if row != curr_row { + builder.buffer.put(curr_row, buf.as_str()); + + skip_sep = true; + buf.clear(); + } + + curr_row = row; + + // TODO: Handle errors. + + match ent { + Some(ent) => { + if let Some(val) = ent.entry { + if !skip_sep { + let _ = write!(buf, "{sep}"); + } + let _ = write!(buf, "{}", val); + skip_sep = false; + } + } + None => { + validity.set_unchecked(row, false); + } + } + })?; + + // Write last row. + builder.buffer.put(curr_row, buf.as_str()); + + Ok(Array::new_with_array_data( + builder.datatype, + builder.buffer.into_data(), + )) +} diff --git a/crates/rayexec_execution/src/functions/scalar/builtin/list/mod.rs b/crates/rayexec_execution/src/functions/scalar/builtin/list/mod.rs index 873947a19..e9ca97c81 100644 --- a/crates/rayexec_execution/src/functions/scalar/builtin/list/mod.rs +++ b/crates/rayexec_execution/src/functions/scalar/builtin/list/mod.rs @@ -3,3 +3,6 @@ pub use list_values::*; mod list_extract; pub use list_extract::*; + +mod list_to_string; +pub use list_to_string::*; diff --git a/crates/rayexec_execution/src/functions/scalar/builtin/mod.rs b/crates/rayexec_execution/src/functions/scalar/builtin/mod.rs index 39215d973..30b9a7118 100644 --- a/crates/rayexec_execution/src/functions/scalar/builtin/mod.rs +++ b/crates/rayexec_execution/src/functions/scalar/builtin/mod.rs @@ -83,6 +83,7 @@ pub static BUILTIN_SCALAR_FUNCTIONS: LazyLock>> = La // List Box::new(list::ListExtract), Box::new(list::ListValues), + Box::new(list::ListToString), // Datetime Box::new(datetime::DatePart), Box::new(datetime::DateTrunc), diff --git a/crates/rayexec_execution/src/functions/scalar/builtin/similarity/l2_distance.rs b/crates/rayexec_execution/src/functions/scalar/builtin/similarity/l2_distance.rs index c7a1924eb..43e39afb7 100644 --- a/crates/rayexec_execution/src/functions/scalar/builtin/similarity/l2_distance.rs +++ b/crates/rayexec_execution/src/functions/scalar/builtin/similarity/l2_distance.rs @@ -11,7 +11,7 @@ use rayexec_bullet::executor::physical_type::{ PhysicalF64, PhysicalStorage, }; -use rayexec_bullet::executor::scalar::{BinaryListReducer, ListExecutor}; +use rayexec_bullet::executor::scalar::{BinaryListExecutor, BinaryListReducer}; use rayexec_error::Result; use crate::expr::Expression; @@ -119,7 +119,9 @@ where buffer: PrimitiveBuffer::with_len(a.logical_len()), }; - ListExecutor::::binary_reduce::>(a, b, builder) + BinaryListExecutor::::binary_reduce::>( + a, b, builder, + ) } } diff --git a/slt/standard/functions/scalars/list_extract.slt b/slt/standard/functions/scalars/list/list_extract.slt similarity index 100% rename from slt/standard/functions/scalars/list_extract.slt rename to slt/standard/functions/scalars/list/list_extract.slt diff --git a/slt/standard/functions/scalars/list/list_to_string.slt b/slt/standard/functions/scalars/list/list_to_string.slt new file mode 100644 index 000000000..05110cbbe --- /dev/null +++ b/slt/standard/functions/scalars/list/list_to_string.slt @@ -0,0 +1,12 @@ +# list_to_string function. + +query T +SELECT list_to_string([4,5,6], ','); +---- +4,5,6 + +query T +SELECT list_to_string([4,5,6], '-'); +---- +4-5-6 + diff --git a/slt/standard/functions/scalars/list_values.slt b/slt/standard/functions/scalars/list/list_values.slt similarity index 100% rename from slt/standard/functions/scalars/list_values.slt rename to slt/standard/functions/scalars/list/list_values.slt From b2f481c07e5ea9031156a88791a47d65865d2f43 Mon Sep 17 00:00:00 2001 From: Sean Smith Date: Thu, 19 Dec 2024 09:28:00 -0600 Subject: [PATCH 2/2] fixup! list_to_string --- crates/rayexec_bullet/src/executor/scalar/list/unary.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/rayexec_bullet/src/executor/scalar/list/unary.rs b/crates/rayexec_bullet/src/executor/scalar/list/unary.rs index 9483be635..032706ad8 100644 --- a/crates/rayexec_bullet/src/executor/scalar/list/unary.rs +++ b/crates/rayexec_bullet/src/executor/scalar/list/unary.rs @@ -33,8 +33,6 @@ impl UnaryListExecutor { (None, None) => { // No validities for parent array or child array. - println!("LEN: {}", array.logical_len()); - for row_idx in 0..array.logical_len() { let sel = unsafe { selection::get_unchecked(selection, row_idx) }; let m = unsafe { metadata.get_unchecked(sel) };