diff --git a/after.txt b/after.txt new file mode 100644 index 0000000000000..ca628c7863f73 --- /dev/null +++ b/after.txt @@ -0,0 +1,49 @@ +=== PhysicalExprAdapter Serialization Example === + +Step 1: Creating sample Parquet data... +Step 2: Setting up session with custom adapter... +Step 3: Creating physical plan with filter... + [Verify] original plan adapter check: true + Original plan has adapter: true + +Step 4: Serializing plan with AdapterPreservingCodec... + [Serialize] Found DataSourceExec with adapter tag: v1 + Serialized 407 bytes + (DataSourceExec with adapter wrapped as PhysicalExtensionNode with child plan) + +Step 5: Deserializing plan with AdapterPreservingCodec... + [Deserialize] Found adapter extension with tag: v1 + [Verify] restored plan adapter check: true + Restored plan has adapter: true + +Step 6: Executing plans and comparing results... + + Original plan results: ++----+ +| id | ++----+ +| 6 | +| 7 | +| 8 | +| 9 | +| 10 | ++----+ + + Restored plan results: ++----+ +| id | ++----+ +| 6 | +| 7 | +| 8 | +| 9 | +| 10 | ++----+ + +=== Example Complete! === +Key takeaways: + 1. PhysicalExtensionCodec provides serialize_physical_plan/deserialize_physical_plan hooks + 2. The wrapper node pattern: metadata in JSON payload, structure in inputs field + 3. Inner plans are included as children via extension.inputs, not encoded to bytes + 4. Both plans produce identical results despite serialization round-trip + 5. Adapters are fully preserved through the serialization round-trip diff --git a/before.txt b/before.txt new file mode 100644 index 0000000000000..cc86f6e441427 --- /dev/null +++ b/before.txt @@ -0,0 +1,49 @@ +=== PhysicalExprAdapter Serialization Example === + +Step 1: Creating sample Parquet data... +Step 2: Setting up session with custom adapter... +Step 3: Creating physical plan with filter... + [Verify] original plan adapter check: true + Original plan has adapter: true + +Step 4: Serializing plan with AdapterPreservingCodec... + [Serialize] Found DataSourceExec with adapter tag: v1 + Serialized 1049 bytes + (DataSourceExec with adapter was wrapped as PhysicalExtensionNode) + +Step 5: Deserializing plan with AdapterPreservingCodec... + [Deserialize] Found adapter extension with tag: v1 + [Verify] restored plan adapter check: true + Restored plan has adapter: true + +Step 6: Executing plans and comparing results... + + Original plan results: ++----+ +| id | ++----+ +| 6 | +| 7 | +| 8 | +| 9 | +| 10 | ++----+ + + Restored plan results: ++----+ +| id | ++----+ +| 6 | +| 7 | +| 8 | +| 9 | +| 10 | ++----+ + +=== Example Complete! === +Key takeaways: + 1. PhysicalExtensionCodec provides serialize_physical_plan/deserialize_physical_plan hooks + 2. Custom metadata can be wrapped as PhysicalExtensionNode + 3. Nested serialization (protobuf + JSON) works seamlessly + 4. Both plans produce identical results despite serialization round-trip + 5. Adapters are fully preserved through the serialization round-trip diff --git a/benchmarks/bench.sh b/benchmarks/bench.sh index 761efa6d591a4..6a3bf471329db 100755 --- a/benchmarks/bench.sh +++ b/benchmarks/bench.sh @@ -783,7 +783,7 @@ run_clickbench_partitioned() { run_clickbench_pushdown() { RESULTS_FILE="${RESULTS_DIR}/clickbench_pushdown.json" echo "RESULTS_FILE: ${RESULTS_FILE}" - echo "Running clickbench (partitioned, 100 files) benchmark with pushdown_filters=true, reorder_filters=true..." + echo "Running clickbench (partitioned, 100 files) benchmark with pushdown_filters=true..." debug_run $CARGO_COMMAND --bin dfbench -- clickbench --pushdown --iterations 5 --path "${DATA_DIR}/hits_partitioned" --queries-path "${SCRIPT_DIR}/queries/clickbench/queries" -o "${RESULTS_FILE}" ${QUERY_ARG} } diff --git a/benchmarks/src/clickbench.rs b/benchmarks/src/clickbench.rs index c0f911c566f4d..098fe269d7b69 100644 --- a/benchmarks/src/clickbench.rs +++ b/benchmarks/src/clickbench.rs @@ -58,7 +58,6 @@ pub struct RunOpt { /// /// Specifically, it enables: /// * `pushdown_filters = true` - /// * `reorder_filters = true` #[arg(long = "pushdown")] pushdown: bool, @@ -196,14 +195,12 @@ impl RunOpt { // Turn on Parquet filter pushdown if requested if self.pushdown { parquet_options.pushdown_filters = true; - parquet_options.reorder_filters = true; } if self.sorted_by.is_some() { // We should compare the dynamic topk optimization when data is sorted, so we make the // assumption that filter pushdown is also enabled in this case. parquet_options.pushdown_filters = true; - parquet_options.reorder_filters = true; } } diff --git a/datafusion-examples/examples/data_io/json_shredding.rs b/datafusion-examples/examples/data_io/json_shredding.rs index ca1513f626245..49619e8a6c1d0 100644 --- a/datafusion-examples/examples/data_io/json_shredding.rs +++ b/datafusion-examples/examples/data_io/json_shredding.rs @@ -91,7 +91,10 @@ pub async fn json_shredding() -> Result<()> { store.put(&path, payload).await?; // Set up query execution - let mut cfg = SessionConfig::new(); + let mut cfg = SessionConfig::default().set( + "datafusion.execution.parquet.filter_pushdown_min_bytes_per_sec", + &ScalarValue::Float64(Some(0.0)), + ); cfg.options_mut().execution.parquet.pushdown_filters = true; let ctx = SessionContext::new_with_config(cfg); ctx.runtime_env().register_object_store( diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs index d71af206c78d5..24c3ea0aa693a 100644 --- a/datafusion/common/src/config.rs +++ b/datafusion/common/src/config.rs @@ -709,11 +709,6 @@ config_namespace! { /// reduce the number of rows decoded. This optimization is sometimes called "late materialization". pub pushdown_filters: bool, default = false - /// (reading) If true, filter expressions evaluated during the parquet decoding operation - /// will be reordered heuristically to minimize the cost of evaluation. If false, - /// the filters are applied in the same order as written in the query - pub reorder_filters: bool, default = false - /// (reading) Force the use of RowSelections for filter results, when /// pushdown_filters is enabled. If false, the reader will automatically /// choose between a RowSelection and a Bitmap based on the number and @@ -743,6 +738,10 @@ config_namespace! { /// (reading) Use any available bloom filters when reading parquet files pub bloom_filter_on_read: bool, default = true + /// (reading) If true, the parquet reader will share work between partitions + /// using morsel-driven execution. This can help mitigate data skew. + pub allow_morsel_driven: bool, default = true + /// (reading) The maximum predicate cache size, in bytes. When /// `pushdown_filters` is enabled, sets the maximum memory used to cache /// the results of predicate evaluation between filter evaluation and @@ -751,6 +750,49 @@ config_namespace! { /// parquet reader setting. 0 means no caching. pub max_predicate_cache_size: Option, default = None + /// (reading) Minimum bytes/sec throughput for adaptive filter pushdown. + /// Filters that achieve at least this throughput (bytes_saved / eval_time) + /// are promoted to row filters. + /// f64::INFINITY = no filters promoted (feature disabled). + /// 0.0 = all filters pushed as row filters (no adaptive logic). + /// Default: 104,857,600 bytes/sec (100 MiB/sec), empirically chosen based on + /// TPC-H, TPC-DS, and ClickBench benchmarks on an m4 MacBook Pro. + /// The optimal value for this setting likely depends on the relative + /// cost of CPU vs. IO in your environment, and to some extent the shape + /// of your query. + /// + /// **Interaction with `pushdown_filters`:** + /// This option only takes effect when `pushdown_filters = true`. + /// When pushdown is disabled, all filters run post-scan and this + /// threshold is ignored. + pub filter_pushdown_min_bytes_per_sec: f64, default = 104_857_600.0 + + /// (reading) Byte-ratio threshold for applying filters one at a time + /// (iterative pruning; aka row-level) vs. all at once (post-scan). + /// The ratio is computed as: (extra filter bytes not in projection) / (projected bytes). + /// Filters whose extra columns consume a smaller fraction than this threshold are placed as row filters. + /// Filters whose extra columns consume a larger fraction are placed as post-scan filters. + /// Note: filter columns that are already in the query projection have zero extra cost, + /// so such filters always start as row filters regardless of this threshold. + /// Default: 0.05 meaning filters that require less than 5% additional bytes beyond the projection + /// are placed as row filters. + /// Set to INF to place all filters as row filters (skip byte-ratio check). + /// Set to 0 to place all filters as post-scan filters (no filter passes the ratio check). + /// + /// **Interaction with `pushdown_filters`:** + /// Only takes effect when `pushdown_filters = true`. + pub filter_collecting_byte_ratio_threshold: f64, default = 0.05 + + /// (reading) Z-score for confidence intervals on filter effectiveness. + /// Controls how much statistical evidence is required before promoting + /// or demoting a filter. Lower values = faster decisions with less + /// confidence. Higher values = more conservative, requiring more data. + /// Default: 2.0 (~95% confidence). + /// + /// **Interaction with `pushdown_filters`:** + /// Only takes effect when `pushdown_filters = true`. + pub filter_confidence_z: f64, default = 2.0 + // The following options affect writing to parquet files // and map to parquet::file::properties::WriterProperties diff --git a/datafusion/common/src/file_options/parquet_writer.rs b/datafusion/common/src/file_options/parquet_writer.rs index a7a1fc6d0bb66..37b2b0f6c24b5 100644 --- a/datafusion/common/src/file_options/parquet_writer.rs +++ b/datafusion/common/src/file_options/parquet_writer.rs @@ -198,7 +198,7 @@ impl ParquetOptions { skip_metadata: _, metadata_size_hint: _, pushdown_filters: _, - reorder_filters: _, + force_filter_selections: _, // not used for writer props allow_single_file_parallelism: _, maximum_parallel_row_group_writers: _, @@ -208,7 +208,11 @@ impl ParquetOptions { binary_as_string: _, // not used for writer props coerce_int96: _, // not used for writer props skip_arrow_metadata: _, + allow_morsel_driven: _, max_predicate_cache_size: _, + filter_pushdown_min_bytes_per_sec: _, // not used for writer props + filter_collecting_byte_ratio_threshold: _, // not used for writer props + filter_confidence_z: _, // not used for writer props } = self; let mut builder = WriterProperties::builder() @@ -447,7 +451,7 @@ mod tests { skip_metadata: defaults.skip_metadata, metadata_size_hint: defaults.metadata_size_hint, pushdown_filters: defaults.pushdown_filters, - reorder_filters: defaults.reorder_filters, + force_filter_selections: defaults.force_filter_selections, allow_single_file_parallelism: defaults.allow_single_file_parallelism, maximum_parallel_row_group_writers: defaults @@ -460,6 +464,11 @@ mod tests { skip_arrow_metadata: defaults.skip_arrow_metadata, coerce_int96: None, max_predicate_cache_size: defaults.max_predicate_cache_size, + allow_morsel_driven: defaults.allow_morsel_driven, + filter_pushdown_min_bytes_per_sec: defaults.filter_pushdown_min_bytes_per_sec, + filter_collecting_byte_ratio_threshold: defaults + .filter_collecting_byte_ratio_threshold, + filter_confidence_z: defaults.filter_confidence_z, } } @@ -561,7 +570,7 @@ mod tests { skip_metadata: global_options_defaults.skip_metadata, metadata_size_hint: global_options_defaults.metadata_size_hint, pushdown_filters: global_options_defaults.pushdown_filters, - reorder_filters: global_options_defaults.reorder_filters, + force_filter_selections: global_options_defaults.force_filter_selections, allow_single_file_parallelism: global_options_defaults .allow_single_file_parallelism, @@ -575,7 +584,13 @@ mod tests { schema_force_view_types: global_options_defaults.schema_force_view_types, binary_as_string: global_options_defaults.binary_as_string, skip_arrow_metadata: global_options_defaults.skip_arrow_metadata, + allow_morsel_driven: global_options_defaults.allow_morsel_driven, coerce_int96: None, + filter_pushdown_min_bytes_per_sec: global_options_defaults + .filter_pushdown_min_bytes_per_sec, + filter_collecting_byte_ratio_threshold: global_options_defaults + .filter_collecting_byte_ratio_threshold, + filter_confidence_z: global_options_defaults.filter_confidence_z, }, column_specific_options, key_value_metadata, diff --git a/datafusion/core/src/dataframe/parquet.rs b/datafusion/core/src/dataframe/parquet.rs index 54dadfd78cbc2..69156bf6756f2 100644 --- a/datafusion/core/src/dataframe/parquet.rs +++ b/datafusion/core/src/dataframe/parquet.rs @@ -152,7 +152,14 @@ mod tests { let plan = df.explain(false, false)?.collect().await?; // Filters all the way to Parquet let formatted = pretty::pretty_format_batches(&plan)?.to_string(); - assert!(formatted.contains("FilterExec: id@0 = 1"), "{formatted}"); + let data_source_exec_row = formatted + .lines() + .find(|line| line.contains("DataSourceExec:")) + .unwrap(); + assert!( + data_source_exec_row.contains("predicate=id@0 = 1"), + "{formatted}" + ); Ok(()) } diff --git a/datafusion/core/src/datasource/physical_plan/parquet.rs b/datafusion/core/src/datasource/physical_plan/parquet.rs index 4c6d915d5bcaa..dc1dbb29894b3 100644 --- a/datafusion/core/src/datasource/physical_plan/parquet.rs +++ b/datafusion/core/src/datasource/physical_plan/parquet.rs @@ -49,8 +49,11 @@ mod tests { use datafusion_common::config::TableParquetOptions; use datafusion_common::test_util::{batches_to_sort_string, batches_to_string}; use datafusion_common::{Result, ScalarValue, assert_contains}; + use datafusion_common_runtime::SpawnedTask; use datafusion_datasource::file_format::FileFormat; - use datafusion_datasource::file_scan_config::FileScanConfigBuilder; + use datafusion_datasource::file_scan_config::{ + FileScanConfig, FileScanConfigBuilder, + }; use datafusion_datasource::source::DataSourceExec; use datafusion_datasource::file::FileSource; @@ -76,7 +79,7 @@ mod tests { use insta::assert_snapshot; use object_store::local::LocalFileSystem; use object_store::path::Path; - use object_store::{ObjectMeta, ObjectStore}; + use object_store::{ObjectMeta, ObjectStore, ObjectStoreExt}; use parquet::arrow::ArrowWriter; use parquet::file::properties::WriterProperties; use tempfile::TempDir; @@ -167,9 +170,11 @@ mod tests { } if self.pushdown_predicate { + let mut opts = source.table_parquet_options().clone(); + opts.global.filter_pushdown_min_bytes_per_sec = 0.0; source = source - .with_pushdown_filters(true) - .with_reorder_filters(true); + .with_table_parquet_options(opts) + .with_pushdown_filters(true); } else { source = source.with_pushdown_filters(false); } @@ -2459,4 +2464,152 @@ mod tests { assert_eq!(calls.len(), 2); assert_eq!(calls, vec![Some(123), Some(456)]); } + + #[tokio::test] + async fn parquet_morsel_driven_execution() -> Result<()> { + let store = + Arc::new(object_store::memory::InMemory::new()) as Arc; + let store_url = ObjectStoreUrl::parse("memory://test").unwrap(); + + let ctx = SessionContext::new(); + ctx.register_object_store(store_url.as_ref(), store.clone()); + + // Create a Parquet file with 100 row groups, each with 10 rows + let schema = Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])); + + let mut out = Vec::new(); + let props = WriterProperties::builder() + .set_max_row_group_row_count(Some(10)) + .build(); + { + let mut writer = + ArrowWriter::try_new(&mut out, Arc::clone(&schema), Some(props))?; + // Write many batches to ensure they are not coalesced and we can verify work distribution + for i in 0..100 { + let batch = RecordBatch::try_new( + Arc::clone(&schema), + vec![Arc::new(Int32Array::from(vec![i; 10]))], + )?; + writer.write(&batch)?; + } + writer.close()?; + } + + let path = Path::from("skewed.parquet"); + store.put(&path, out.into()).await?; + let meta = store.head(&path).await?; + + // Set up DataSourceExec with 2 partitions, but the file is only in partition 0 (skewed) + let source = Arc::new(ParquetSource::new(schema)); + let config = FileScanConfigBuilder::new(store_url, source) + .with_file_group(FileGroup::new(vec![PartitionedFile::new_from_meta(meta)])) + .with_file_group(FileGroup::new(vec![])) // Partition 1 is empty + .with_morsel_driven(true) + .build(); + + let exec = DataSourceExec::from_data_source(config); + + // Execute both partitions concurrently + let task_ctx = ctx.task_ctx(); + let stream0 = exec.execute(0, Arc::clone(&task_ctx))?; + let stream1 = exec.execute(1, Arc::clone(&task_ctx))?; + + let handle0 = SpawnedTask::spawn(async move { + let mut count = 0; + let mut s = stream0; + while let Some(batch) = s.next().await { + count += batch.unwrap().num_rows(); + tokio::task::yield_now().await; + } + count + }); + + let handle1 = SpawnedTask::spawn(async move { + let mut count = 0; + let mut s = stream1; + while let Some(batch) = s.next().await { + count += batch.unwrap().num_rows(); + tokio::task::yield_now().await; + } + count + }); + + let count0 = handle0.await.unwrap(); + let count1 = handle1.await.unwrap(); + + // Total rows should be 1000 + assert_eq!(count0 + count1, 1000); + + // Since it's morsel-driven, both partitions should have done some work + // because the work from partition 0 (the single file) was split into + // individual row groups and shared via the shared queue. + assert!(count0 > 0, "Partition 0 should have produced rows"); + assert!(count1 > 0, "Partition 1 should have produced rows"); + + // Test re-executability: executing the same plan again should work + let stream0 = exec.execute(0, Arc::clone(&task_ctx))?; + let stream1 = exec.execute(1, Arc::clone(&task_ctx))?; + + let mut count = 0; + let mut s0 = stream0; + while let Some(batch) = s0.next().await { + count += batch.unwrap().num_rows(); + } + let mut s1 = stream1; + while let Some(batch) = s1.next().await { + count += batch.unwrap().num_rows(); + } + assert_eq!( + count, 1000, + "Second execution should also produce 1000 rows" + ); + + Ok(()) + } + + #[tokio::test] + async fn parquet_morsel_driven_enabled_by_default() -> Result<()> { + let tmp_dir = TempDir::new()?; + let path = tmp_dir.path().join("test.parquet"); + let schema = Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])); + let batch = RecordBatch::try_new( + Arc::clone(&schema), + vec![Arc::new(Int32Array::from(vec![1, 2, 3]))], + )?; + + let file = File::create(&path)?; + let mut writer = ArrowWriter::try_new(file, Arc::clone(&schema), None)?; + writer.write(&batch)?; + writer.close()?; + + let ctx = SessionContext::new(); + ctx.register_parquet("t", path.to_str().unwrap(), ParquetReadOptions::default()) + .await?; + + let df = ctx.sql("SELECT * FROM t").await?; + let plan = df.create_physical_plan().await?; + + // Plan should be a ProjectionExec over a DataSourceExec + let ds_exec = if let Some(ds) = plan.as_any().downcast_ref::() { + ds + } else { + plan.children()[0] + .as_any() + .downcast_ref::() + .expect("Expected DataSourceExec") + }; + + let config = ds_exec + .data_source() + .as_any() + .downcast_ref::() + .expect("Expected FileScanConfig"); + + assert!( + config.morsel_driven, + "morsel_driven should be enabled by default for Parquet" + ); + + Ok(()) + } } diff --git a/datafusion/core/src/test_util/parquet.rs b/datafusion/core/src/test_util/parquet.rs index dba017f83ba1e..c2e10897bfe2a 100644 --- a/datafusion/core/src/test_util/parquet.rs +++ b/datafusion/core/src/test_util/parquet.rs @@ -57,8 +57,6 @@ pub struct TestParquetFile { pub struct ParquetScanOptions { /// Enable pushdown filters pub pushdown_filters: bool, - /// enable reordering filters - pub reorder_filters: bool, /// enable page index pub enable_page_index: bool, } @@ -68,8 +66,9 @@ impl ParquetScanOptions { pub fn config(&self) -> SessionConfig { let mut config = ConfigOptions::new(); config.execution.parquet.pushdown_filters = self.pushdown_filters; - config.execution.parquet.reorder_filters = self.reorder_filters; config.execution.parquet.enable_page_index = self.enable_page_index; + // Disable adaptive filter selection for tests that expect deterministic pushdown + config.execution.parquet.filter_pushdown_min_bytes_per_sec = 0.0; config.into() } } diff --git a/datafusion/core/tests/fuzz_cases/topk_filter_pushdown.rs b/datafusion/core/tests/fuzz_cases/topk_filter_pushdown.rs index d14afaf1b3267..94933c59070b7 100644 --- a/datafusion/core/tests/fuzz_cases/topk_filter_pushdown.rs +++ b/datafusion/core/tests/fuzz_cases/topk_filter_pushdown.rs @@ -227,8 +227,59 @@ impl RunQueryResult { format!("{}", pretty_format_batches(&self.result).unwrap()) } + /// Extract ORDER BY column names from the query. + /// The query format is always: + /// `SELECT * FROM test_table ORDER BY , ... LIMIT ` + fn sort_columns(&self) -> Vec { + let order_by_start = self.query.find("ORDER BY").unwrap() + "ORDER BY".len(); + let limit_start = self.query.rfind(" LIMIT").unwrap(); + self.query[order_by_start..limit_start] + .trim() + .split(',') + .map(|part| part.split_whitespace().next().unwrap().to_string()) + .collect() + } + + /// Project `batches` to only include the named columns. + fn project_columns(batches: &[RecordBatch], cols: &[String]) -> Vec { + batches + .iter() + .map(|b| { + let indices: Vec = cols + .iter() + .filter_map(|c| b.schema().index_of(c).ok()) + .collect(); + b.project(&indices).unwrap() + }) + .collect() + } + fn is_ok(&self) -> bool { - self.expected_formatted() == self.result_formatted() + if self.expected_formatted() == self.result_formatted() { + return true; + } + // If the full results differ, compare only the ORDER BY column values. + // + // For queries with ORDER BY LIMIT k, multiple rows may tie on the + // sort key (e.g. two rows with id=27 for ORDER BY id DESC LIMIT 1). + // SQL permits returning any of the tied rows, so with vs without dynamic + // filter pushdown may legitimately return different tied rows. + // + // The dynamic filter must not change the *sort-key values* of the top-k + // result. We verify correctness by: + // 1. Checking the row counts match (wrong count is always a bug). + // 2. Projecting both results down to only the ORDER BY columns and + // comparing those (tied rows may differ, but the sort-key values must not). + let expected_rows: usize = self.expected.iter().map(|b| b.num_rows()).sum(); + let result_rows: usize = self.result.iter().map(|b| b.num_rows()).sum(); + if expected_rows != result_rows { + return false; + } + let sort_cols = self.sort_columns(); + let expected_keys = Self::project_columns(&self.expected, &sort_cols); + let result_keys = Self::project_columns(&self.result, &sort_cols); + format!("{}", pretty_format_batches(&expected_keys).unwrap()) + == format!("{}", pretty_format_batches(&result_keys).unwrap()) } } diff --git a/datafusion/core/tests/parquet/filter_pushdown.rs b/datafusion/core/tests/parquet/filter_pushdown.rs index e6266b2c088d7..6a5fc2c9beeed 100644 --- a/datafusion/core/tests/parquet/filter_pushdown.rs +++ b/datafusion/core/tests/parquet/filter_pushdown.rs @@ -444,7 +444,6 @@ impl<'a> TestCase<'a> { .read_with_options( ParquetScanOptions { pushdown_filters: false, - reorder_filters: false, enable_page_index: false, }, filter, @@ -455,7 +454,6 @@ impl<'a> TestCase<'a> { .read_with_options( ParquetScanOptions { pushdown_filters: true, - reorder_filters: false, enable_page_index: false, }, filter, @@ -464,24 +462,10 @@ impl<'a> TestCase<'a> { assert_eq!(no_pushdown, only_pushdown); - let pushdown_and_reordering = self - .read_with_options( - ParquetScanOptions { - pushdown_filters: true, - reorder_filters: true, - enable_page_index: false, - }, - filter, - ) - .await; - - assert_eq!(no_pushdown, pushdown_and_reordering); - let page_index_only = self .read_with_options( ParquetScanOptions { pushdown_filters: false, - reorder_filters: false, enable_page_index: true, }, filter, @@ -489,18 +473,17 @@ impl<'a> TestCase<'a> { .await; assert_eq!(no_pushdown, page_index_only); - let pushdown_reordering_and_page_index = self + let pushdown_and_page_index = self .read_with_options( ParquetScanOptions { pushdown_filters: true, - reorder_filters: true, enable_page_index: true, }, filter, ) .await; - assert_eq!(no_pushdown, pushdown_reordering_and_page_index); + assert_eq!(no_pushdown, pushdown_and_page_index); } /// Reads data from a test parquet file using the specified scan options @@ -633,6 +616,11 @@ async fn predicate_cache_default() -> datafusion_common::Result<()> { async fn predicate_cache_pushdown_default() -> datafusion_common::Result<()> { let mut config = SessionConfig::new(); config.options_mut().execution.parquet.pushdown_filters = true; + config + .options_mut() + .execution + .parquet + .filter_pushdown_min_bytes_per_sec = 0.0; let ctx = SessionContext::new_with_config(config); // The cache is on by default, and used when filter pushdown is enabled PredicateCacheTest { @@ -647,6 +635,11 @@ async fn predicate_cache_pushdown_default() -> datafusion_common::Result<()> { async fn predicate_cache_stats_issue_19561() -> datafusion_common::Result<()> { let mut config = SessionConfig::new(); config.options_mut().execution.parquet.pushdown_filters = true; + config + .options_mut() + .execution + .parquet + .filter_pushdown_min_bytes_per_sec = 0.0; // force to get multiple batches to trigger repeated metric compound bug config.options_mut().execution.batch_size = 1; let ctx = SessionContext::new_with_config(config); @@ -664,6 +657,11 @@ async fn predicate_cache_pushdown_default_selections_only() -> datafusion_common::Result<()> { let mut config = SessionConfig::new(); config.options_mut().execution.parquet.pushdown_filters = true; + config + .options_mut() + .execution + .parquet + .filter_pushdown_min_bytes_per_sec = 0.0; // forcing filter selections minimizes the number of rows read from the cache config .options_mut() diff --git a/datafusion/core/tests/parquet/row_group_pruning.rs b/datafusion/core/tests/parquet/row_group_pruning.rs index 445ae7e97f228..35e2ec6cde7bc 100644 --- a/datafusion/core/tests/parquet/row_group_pruning.rs +++ b/datafusion/core/tests/parquet/row_group_pruning.rs @@ -382,7 +382,11 @@ async fn prune_disabled() { .await; println!("{}", output.description()); - // This should not prune any + // Row group stats pruning is disabled, so 0 row groups are pruned by statistics. + // Bloom filter runs next and matches all 4 row groups (bloom filters don't help + // for range/inequality predicates like `nanos < threshold`). Page index pruning + // runs afterwards and can produce row-level selections, but those don't affect + // the bloom filter matched count. The query result is still correct. assert_eq!(output.predicate_evaluation_errors(), Some(0)); assert_eq!(output.row_groups_matched(), Some(4)); assert_eq!(output.row_groups_pruned(), Some(0)); diff --git a/datafusion/core/tests/physical_optimizer/filter_pushdown.rs b/datafusion/core/tests/physical_optimizer/filter_pushdown.rs index 99db81d34d8fa..3438532ba6f03 100644 --- a/datafusion/core/tests/physical_optimizer/filter_pushdown.rs +++ b/datafusion/core/tests/physical_optimizer/filter_pushdown.rs @@ -263,7 +263,7 @@ async fn test_dynamic_filter_pushdown_through_hash_join_with_topk() { - SortExec: TopK(fetch=2), expr=[e@4 ASC], preserve_partitioning=[false] - HashJoinExec: mode=Partitioned, join_type=Inner, on=[(a@0, d@0)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[d, e, f], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[d, e, f], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ empty ]) AND DynamicFilter [ empty ] " ); @@ -283,11 +283,11 @@ async fn test_dynamic_filter_pushdown_through_hash_join_with_topk() { // NOTE: We dropped the CASE expression here because we now optimize that away if there's only 1 partition insta::assert_snapshot!( format_plan_for_test(&plan), - @r" + @" - SortExec: TopK(fetch=2), expr=[e@4 ASC], preserve_partitioning=[false], filter=[e@4 IS NULL OR e@4 < bb] - HashJoinExec: mode=Partitioned, join_type=Inner, on=[(a@0, d@0)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[d, e, f], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ d@0 >= aa AND d@0 <= ab AND d@0 IN (SET) ([aa, ab]) ] AND DynamicFilter [ e@1 IS NULL OR e@1 < bb ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[d, e, f], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ d@0 >= aa AND d@0 <= ab AND d@0 IN (SET) ([aa, ab]) ]) AND DynamicFilter [ e@1 IS NULL OR e@1 < bb ] " ); } @@ -1009,7 +1009,7 @@ async fn test_hashjoin_dynamic_filter_pushdown() { Ok: - HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(a@0, a@0), (b@1, b@1)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ empty ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ empty ]) ", ); @@ -1043,7 +1043,7 @@ async fn test_hashjoin_dynamic_filter_pushdown() { @r" - HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(a@0, a@0), (b@1, b@1)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ a@0 >= aa AND a@0 <= ab AND b@1 >= ba AND b@1 <= bb AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:ba}, {c0:ab,c1:bb}]) ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ a@0 >= aa AND a@0 <= ab AND b@1 >= ba AND b@1 <= bb AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:ba}, {c0:ab,c1:bb}]) ]) " ); } @@ -1219,7 +1219,7 @@ async fn test_hashjoin_dynamic_filter_pushdown_partitioned() { - RepartitionExec: partitioning=Hash([a@0, b@1], 12), input_partitions=1 - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - RepartitionExec: partitioning=Hash([a@0, b@1], 12), input_partitions=1 - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ empty ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ empty ]) " ); @@ -1253,7 +1253,7 @@ async fn test_hashjoin_dynamic_filter_pushdown_partitioned() { - RepartitionExec: partitioning=Hash([a@0, b@1], 12), input_partitions=1 - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - RepartitionExec: partitioning=Hash([a@0, b@1], 12), input_partitions=1 - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ CASE hash_repartition % 12 WHEN 2 THEN a@0 >= ab AND a@0 <= ab AND b@1 >= bb AND b@1 <= bb AND struct(a@0, b@1) IN (SET) ([{c0:ab,c1:bb}]) WHEN 4 THEN a@0 >= aa AND a@0 <= aa AND b@1 >= ba AND b@1 <= ba AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:ba}]) ELSE false END ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ CASE hash_repartition % 12 WHEN 2 THEN a@0 >= ab AND a@0 <= ab AND b@1 >= bb AND b@1 <= bb AND struct(a@0, b@1) IN (SET) ([{c0:ab,c1:bb}]) WHEN 4 THEN a@0 >= aa AND a@0 <= aa AND b@1 >= ba AND b@1 <= ba AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:ba}]) ELSE false END ]) " ); @@ -1271,7 +1271,7 @@ async fn test_hashjoin_dynamic_filter_pushdown_partitioned() { - RepartitionExec: partitioning=Hash([a@0, b@1], 12), input_partitions=1 - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - RepartitionExec: partitioning=Hash([a@0, b@1], 12), input_partitions=1 - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ a@0 >= aa AND a@0 <= ab AND b@1 >= ba AND b@1 <= bb AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:ba}, {c0:ab,c1:bb}]) ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ a@0 >= aa AND a@0 <= ab AND b@1 >= ba AND b@1 <= bb AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:ba}, {c0:ab,c1:bb}]) ]) " ); @@ -1411,7 +1411,7 @@ async fn test_hashjoin_dynamic_filter_pushdown_collect_left() { - HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(a@0, a@0), (b@1, b@1)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - RepartitionExec: partitioning=Hash([a@0, b@1], 12), input_partitions=1 - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ empty ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ empty ]) " ); @@ -1443,7 +1443,7 @@ async fn test_hashjoin_dynamic_filter_pushdown_collect_left() { - HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(a@0, a@0), (b@1, b@1)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true - RepartitionExec: partitioning=Hash([a@0, b@1], 12), input_partitions=1 - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ a@0 >= aa AND a@0 <= ab AND b@1 >= ba AND b@1 <= bb AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:ba}, {c0:ab,c1:bb}]) ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, e], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ a@0 >= aa AND a@0 <= ab AND b@1 >= ba AND b@1 <= bb AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:ba}, {c0:ab,c1:bb}]) ]) " ); @@ -1585,8 +1585,8 @@ async fn test_nested_hashjoin_dynamic_filter_pushdown() { - HashJoinExec: mode=Partitioned, join_type=Inner, on=[(a@0, b@0)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, x], file_type=test, pushdown_supported=true - HashJoinExec: mode=Partitioned, join_type=Inner, on=[(c@1, d@0)] - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[b, c, y], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ empty ] - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[d, z], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ empty ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[b, c, y], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ empty ]) + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[d, z], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ empty ]) ", ); @@ -1616,8 +1616,8 @@ async fn test_nested_hashjoin_dynamic_filter_pushdown() { - HashJoinExec: mode=Partitioned, join_type=Inner, on=[(a@0, b@0)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, x], file_type=test, pushdown_supported=true - HashJoinExec: mode=Partitioned, join_type=Inner, on=[(c@1, d@0)] - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[b, c, y], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ b@0 >= aa AND b@0 <= ab AND b@0 IN (SET) ([aa, ab]) ] - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[d, z], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ d@0 >= ca AND d@0 <= cb AND d@0 IN (SET) ([ca, cb]) ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[b, c, y], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ b@0 >= aa AND b@0 <= ab AND b@0 IN (SET) ([aa, ab]) ]) + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[d, z], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ d@0 >= ca AND d@0 <= cb AND d@0 IN (SET) ([ca, cb]) ]) " ); } @@ -1949,6 +1949,11 @@ async fn test_topk_dynamic_filter_pushdown_integration() { let mut cfg = SessionConfig::new(); cfg.options_mut().execution.parquet.pushdown_filters = true; cfg.options_mut().execution.parquet.max_row_group_size = 128; + // Always pushdown filters into row filters for this test + cfg.options_mut() + .execution + .parquet + .filter_pushdown_min_bytes_per_sec = 0.0; let ctx = SessionContext::new_with_config(cfg); ctx.register_object_store( ObjectStoreUrl::parse("memory://").unwrap().as_ref(), @@ -3308,7 +3313,7 @@ async fn test_hashjoin_dynamic_filter_all_partitions_empty() { - RepartitionExec: partitioning=Hash([a@0, b@1], 4), input_partitions=1 - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b], file_type=test, pushdown_supported=true - RepartitionExec: partitioning=Hash([a@0, b@1], 4), input_partitions=1 - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ empty ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ empty ]) " ); @@ -3333,7 +3338,7 @@ async fn test_hashjoin_dynamic_filter_all_partitions_empty() { - RepartitionExec: partitioning=Hash([a@0, b@1], 4), input_partitions=1 - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b], file_type=test, pushdown_supported=true - RepartitionExec: partitioning=Hash([a@0, b@1], 4), input_partitions=1 - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ false ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ false ]) " ); } @@ -3435,7 +3440,7 @@ async fn test_hashjoin_dynamic_filter_with_nulls() { @r" - HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(a@0, a@0), (b@1, b@1)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b], file_type=test, pushdown_supported=true - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ empty ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ empty ]) " ); @@ -3458,7 +3463,7 @@ async fn test_hashjoin_dynamic_filter_with_nulls() { @r" - HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(a@0, a@0), (b@1, b@1)] - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b], file_type=test, pushdown_supported=true - - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true, predicate=DynamicFilter [ a@0 >= aa AND a@0 <= ab AND b@1 >= 1 AND b@1 <= 2 AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:1}, {c0:,c1:2}, {c0:ab,c1:}]) ] + - DataSourceExec: file_groups={1 group: [[test.parquet]]}, projection=[a, b, c], file_type=test, pushdown_supported=true, predicate=Optional(DynamicFilter [ a@0 >= aa AND a@0 <= ab AND b@1 >= 1 AND b@1 <= 2 AND struct(a@0, b@1) IN (SET) ([{c0:aa,c1:1}, {c0:,c1:2}, {c0:ab,c1:}]) ]) " ); diff --git a/datafusion/core/tests/sql/explain_analyze.rs b/datafusion/core/tests/sql/explain_analyze.rs index 5f62f7204eff1..e7d5e28a44803 100644 --- a/datafusion/core/tests/sql/explain_analyze.rs +++ b/datafusion/core/tests/sql/explain_analyze.rs @@ -862,7 +862,7 @@ async fn parquet_explain_analyze() { .to_string(); // should contain aggregated stats - assert_contains!(&formatted, "output_rows=8"); + assert_contains!(&formatted, "output_rows=5"); assert_contains!( &formatted, "row_groups_pruned_bloom_filter=1 total \u{2192} 1 matched" diff --git a/datafusion/datasource-parquet/benches/parquet_nested_filter_pushdown.rs b/datafusion/datasource-parquet/benches/parquet_nested_filter_pushdown.rs index 02137b5a1d288..b76baf83f6e1a 100644 --- a/datafusion/datasource-parquet/benches/parquet_nested_filter_pushdown.rs +++ b/datafusion/datasource-parquet/benches/parquet_nested_filter_pushdown.rs @@ -24,6 +24,7 @@ use arrow::array::{ use arrow::datatypes::{DataType, Field, Schema, SchemaRef}; use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use datafusion_common::ScalarValue; +use datafusion_datasource_parquet::selectivity::SelectivityTracker; use datafusion_datasource_parquet::{ParquetFileMetrics, build_row_filter}; use datafusion_expr::{Expr, col}; use datafusion_functions_nested::expr_fn::array_has; @@ -115,10 +116,28 @@ fn scan_with_predicate( let file_metrics = ParquetFileMetrics::new(0, &path.display().to_string(), &metrics); let builder = if pushdown { - if let Some(row_filter) = - build_row_filter(predicate, file_schema, &metadata, false, &file_metrics)? - { - builder.with_row_filter(row_filter) + let tracker = Arc::new(SelectivityTracker::new()); + let projection_bytes: usize = (0..metadata + .row_groups() + .first() + .map_or(0, |rg| rg.num_columns())) + .map(|i| { + metadata + .row_groups() + .iter() + .map(|rg| rg.column(i).compressed_size() as usize) + .sum::() + }) + .sum(); + if let Some(result) = build_row_filter( + vec![(0, Arc::clone(predicate))], + file_schema, + &metadata, + projection_bytes, + &file_metrics, + &tracker, + )? { + builder.with_row_filter(result.row_filter) } else { builder } diff --git a/datafusion/datasource-parquet/src/file_format.rs b/datafusion/datasource-parquet/src/file_format.rs index edbdd618edb05..29b7dac621ad2 100644 --- a/datafusion/datasource-parquet/src/file_format.rs +++ b/datafusion/datasource-parquet/src/file_format.rs @@ -507,6 +507,12 @@ impl FileFormat for ParquetFormat { ) -> Result> { let mut metadata_size_hint = None; + let filter_pushdown_min_bytes_per_sec = state + .config_options() + .execution + .parquet + .filter_pushdown_min_bytes_per_sec; + if let Some(metadata) = self.metadata_size_hint() { metadata_size_hint = Some(metadata); } @@ -517,7 +523,10 @@ impl FileFormat for ParquetFormat { .downcast_ref::() .cloned() .ok_or_else(|| internal_datafusion_err!("Expected ParquetSource"))?; - source = source.with_table_parquet_options(self.options.clone()); + let mut options = self.options.clone(); + options.global.filter_pushdown_min_bytes_per_sec = + filter_pushdown_min_bytes_per_sec; + source = source.with_table_parquet_options(options); // Use the CachedParquetFileReaderFactory let metadata_cache = state.runtime_env().cache_manager.get_file_metadata_cache(); @@ -536,6 +545,7 @@ impl FileFormat for ParquetFormat { let conf = FileScanConfigBuilder::from(conf) .with_source(Arc::new(source)) + .with_morsel_driven(self.options.global.allow_morsel_driven) .build(); Ok(DataSourceExec::from_data_source(conf)) } diff --git a/datafusion/datasource-parquet/src/metrics.rs b/datafusion/datasource-parquet/src/metrics.rs index 2d6fb69270bf3..1496da8d50775 100644 --- a/datafusion/datasource-parquet/src/metrics.rs +++ b/datafusion/datasource-parquet/src/metrics.rs @@ -91,6 +91,8 @@ pub struct ParquetFileMetrics { /// number of rows that were stored in the cache after evaluating predicates /// reused for the output. pub predicate_cache_records: Gauge, + //// Time spent applying filters + pub filter_apply_time: Time, } impl ParquetFileMetrics { @@ -186,6 +188,10 @@ impl ParquetFileMetrics { .with_new_label("filename", filename.to_string()) .gauge("predicate_cache_records", partition); + let filter_apply_time = MetricBuilder::new(metrics) + .with_new_label("filename", filename.to_string()) + .subset_time("filter_apply_time", partition); + Self { files_ranges_pruned_statistics, predicate_evaluation_errors, @@ -205,6 +211,7 @@ impl ParquetFileMetrics { scan_efficiency_ratio, predicate_cache_inner_records, predicate_cache_records, + filter_apply_time, } } } diff --git a/datafusion/datasource-parquet/src/mod.rs b/datafusion/datasource-parquet/src/mod.rs index 0e137a706fad7..b1c8d93d169a4 100644 --- a/datafusion/datasource-parquet/src/mod.rs +++ b/datafusion/datasource-parquet/src/mod.rs @@ -29,6 +29,7 @@ mod page_filter; mod reader; mod row_filter; mod row_group_filter; +pub mod selectivity; mod sort; pub mod source; mod supported_predicates; @@ -39,6 +40,7 @@ pub use file_format::*; pub use metrics::ParquetFileMetrics; pub use page_filter::PagePruningAccessPlanFilter; pub use reader::*; // Expose so downstream crates can use it +pub use row_filter::RowFilterWithMetrics; pub use row_filter::build_row_filter; pub use row_filter::can_expr_be_pushed_down_with_schemas; pub use row_group_filter::RowGroupAccessPlanFilter; diff --git a/datafusion/datasource-parquet/src/opener.rs b/datafusion/datasource-parquet/src/opener.rs index 108e8c5752017..d6299bc8cc586 100644 --- a/datafusion/datasource-parquet/src/opener.rs +++ b/datafusion/datasource-parquet/src/opener.rs @@ -15,19 +15,26 @@ // specific language governing permissions and limitations // under the License. -//! [`ParquetOpener`] for opening Parquet files +//! [`ParquetOpener`] for opening Parquet files. +//! +//! Implements the adaptive filter feedback loop: filters partitioned by +//! [`SelectivityTracker`] are either +//! pushed as row-level predicates or applied post-scan, and per-batch metrics +//! are fed back into the tracker for future promotion/demotion decisions. use crate::page_filter::PagePruningAccessPlanFilter; use crate::row_group_filter::RowGroupAccessPlanFilter; +use crate::selectivity::{PartitionedFilters, SelectivityTracker}; use crate::{ ParquetAccessPlan, ParquetFileMetrics, ParquetFileReaderFactory, apply_file_schema_type_coercions, coerce_int96_to_resolution, row_filter, }; -use arrow::array::{RecordBatch, RecordBatchOptions}; +use arrow::array::{BooleanArray, RecordBatch, RecordBatchOptions}; use arrow::datatypes::DataType; use datafusion_datasource::file_stream::{FileOpenFuture, FileOpener}; +use datafusion_physical_expr::conjunction; use datafusion_physical_expr::projection::ProjectionExprs; -use datafusion_physical_expr::utils::reassign_expr_columns; +use datafusion_physical_expr::utils::{collect_columns, reassign_expr_columns}; use datafusion_physical_expr_adapter::replace_columns_with_literals; use std::collections::HashMap; use std::pin::Pin; @@ -40,7 +47,7 @@ use datafusion_common::stats::Precision; use datafusion_common::{ ColumnStatistics, DataFusionError, Result, ScalarValue, Statistics, exec_err, }; -use datafusion_datasource::{PartitionedFile, TableSchema}; +use datafusion_datasource::{FileRange, PartitionedFile, TableSchema}; use datafusion_physical_expr::simplifier::PhysicalExprSimplifier; use datafusion_physical_expr_adapter::PhysicalExprAdapterFactory; use datafusion_physical_expr_common::physical_expr::{ @@ -56,6 +63,7 @@ use crate::sort::reverse_row_selection; use datafusion_common::config::EncryptionFactoryOptions; #[cfg(feature = "parquet_encryption")] use datafusion_execution::parquet_encryption::EncryptionFactory; +use futures::future::{BoxFuture, ready}; use futures::{Stream, StreamExt, TryStreamExt, ready}; use log::debug; use parquet::arrow::arrow_reader::metrics::ArrowReaderMetrics; @@ -64,7 +72,9 @@ use parquet::arrow::arrow_reader::{ }; use parquet::arrow::async_reader::AsyncFileReader; use parquet::arrow::{ParquetRecordBatchStreamBuilder, ProjectionMask}; +use parquet::file::metadata::ParquetMetaData; use parquet::file::metadata::{PageIndexPolicy, ParquetMetaDataReader, RowGroupMetaData}; +use parquet::schema::types::SchemaDescriptor; /// Implements [`FileOpener`] for a parquet file pub(super) struct ParquetOpener { @@ -78,8 +88,9 @@ pub(super) struct ParquetOpener { pub(crate) limit: Option, /// If should keep the output rows in order pub preserve_order: bool, - /// Optional predicate to apply during the scan - pub predicate: Option>, + /// Optional predicate conjuncts with stable FilterIds for selectivity tracking + pub predicate_conjuncts: + Option)>>, /// Table schema, including partition columns. pub table_schema: TableSchema, /// Optional hint for how large the initial request to read parquet metadata @@ -90,10 +101,8 @@ pub(super) struct ParquetOpener { /// Factory for instantiating parquet reader pub parquet_file_reader_factory: Arc, /// Should the filters be evaluated during the parquet scan using - /// [`DataFusionArrowPredicate`](row_filter::DatafusionArrowPredicate)? + /// `DatafusionArrowPredicateWithMetrics`? pub pushdown_filters: bool, - /// Should the filters be reordered to optimize the scan? - pub reorder_filters: bool, /// Should we force the reader to use RowSelections for filtering pub force_filter_selections: bool, /// Should the page index be read from parquet files, if present, to skip @@ -120,6 +129,17 @@ pub(super) struct ParquetOpener { pub max_predicate_cache_size: Option, /// Whether to read row groups in reverse order pub reverse_row_groups: bool, + /// Shared selectivity tracker for adaptive filter reordering. + /// Each opener reads stats and decides which filters to push down. + pub selectivity_tracker: Arc, +} + +/// A morsel of work for Parquet execution, containing cached metadata and an access plan. +pub struct ParquetMorsel { + /// Cached Parquet metadata + pub metadata: Arc, + /// Access plan for this morsel (usually selecting a single row group) + pub access_plan: ParquetAccessPlan, } /// Represents a prepared access plan with optional row selection @@ -130,6 +150,13 @@ pub(crate) struct PreparedAccessPlan { pub(crate) row_selection: Option, } +struct RowGroupStatisticsPruningContext<'a> { + physical_file_schema: &'a SchemaRef, + parquet_schema: &'a SchemaDescriptor, + predicate: &'a PruningPredicate, + file_metrics: &'a ParquetFileMetrics, +} + impl PreparedAccessPlan { /// Create a new prepared access plan from a ParquetAccessPlan pub(crate) fn from_access_plan( @@ -146,10 +173,7 @@ impl PreparedAccessPlan { } /// Reverse the access plan for reverse scanning - pub(crate) fn reverse( - mut self, - file_metadata: &parquet::file::metadata::ParquetMetaData, - ) -> Result { + pub(crate) fn reverse(mut self, file_metadata: &ParquetMetaData) -> Result { // Get the row group indexes before reversing let row_groups_to_scan = self.row_group_indexes.clone(); @@ -180,7 +204,297 @@ impl PreparedAccessPlan { } } +impl ParquetOpener { + fn build_row_group_access_filter( + file_name: &str, + extensions: Option>, + row_group_count: usize, + row_group_metadata: &[RowGroupMetaData], + file_range: Option<&FileRange>, + stats_pruning: Option>, + ) -> Result { + let mut row_groups = RowGroupAccessPlanFilter::new(create_initial_plan( + file_name, + extensions, + row_group_count, + )?); + + if let Some(range) = file_range { + row_groups.prune_by_range(row_group_metadata, range); + } + + if let Some(stats_pruning) = stats_pruning { + row_groups.prune_by_statistics( + stats_pruning.physical_file_schema.as_ref(), + stats_pruning.parquet_schema, + row_group_metadata, + stats_pruning.predicate, + stats_pruning.file_metrics, + ); + } + + Ok(row_groups) + } +} + impl FileOpener for ParquetOpener { + fn is_leaf_morsel(&self, file: &PartitionedFile) -> bool { + file.extensions + .as_ref() + .map(|e| e.is::()) + .unwrap_or(false) + } + + fn morselize( + &self, + partitioned_file: PartitionedFile, + ) -> BoxFuture<'static, Result>> { + if partitioned_file + .extensions + .as_ref() + .map(|e| e.is::()) + .unwrap_or(false) + { + return Box::pin(ready(Ok(vec![partitioned_file]))); + } + + let file_metrics = ParquetFileMetrics::new( + self.partition_index, + partitioned_file.object_meta.location.as_ref(), + &self.metrics, + ); + let file_name = partitioned_file.object_meta.location.to_string(); + let file_range = partitioned_file.range.clone(); + let extensions = partitioned_file.extensions.clone(); + + let metadata_size_hint = partitioned_file + .metadata_size_hint + .or(self.metadata_size_hint); + + let mut async_file_reader: Box = + match self.parquet_file_reader_factory.create_reader( + self.partition_index, + partitioned_file.clone(), + metadata_size_hint, + &self.metrics, + ) { + Ok(reader) => reader, + Err(e) => return Box::pin(ready(Err(e))), + }; + + let options = + ArrowReaderOptions::new().with_page_index_policy(PageIndexPolicy::Skip); + #[cfg(feature = "parquet_encryption")] + let encryption_context = self.get_encryption_context(); + + let expr_adapter_factory = Arc::clone(&self.expr_adapter_factory); + let table_schema = self.table_schema.clone(); + let predicate: Option> = self + .predicate_conjuncts + .as_ref() + .map(|c| conjunction(c.iter().map(|(_, e)| Arc::clone(e)))); + let metrics = self.metrics.clone(); + let enable_row_group_stats_pruning = self.enable_row_group_stats_pruning; + let enable_bloom_filter = self.enable_bloom_filter; + let enable_page_index = self.enable_page_index; + let limit = self.limit; + let preserve_order = self.preserve_order; + let parquet_file_reader_factory = Arc::clone(&self.parquet_file_reader_factory); + let partition_index = self.partition_index; + + Box::pin(async move { + #[cfg(feature = "parquet_encryption")] + let options = if let Some(fd_val) = encryption_context + .get_file_decryption_properties(&partitioned_file.object_meta.location) + .await? + { + options.with_file_decryption_properties(Arc::clone(&fd_val)) + } else { + options + }; + + let predicate_creation_errors = MetricBuilder::new(&metrics) + .global_counter("num_predicate_creation_errors"); + + // Step: try to prune the file using file-level statistics before loading + // parquet metadata. This avoids the I/O cost of reading metadata when + // file-level stats (available from the catalog) indicate no rows can match. + if let Some(pred) = predicate.as_ref() { + let logical_file_schema = Arc::clone(table_schema.file_schema()); + if let Some(mut file_pruner) = FilePruner::try_new( + Arc::clone(pred), + &logical_file_schema, + &partitioned_file, + predicate_creation_errors.clone(), + ) && file_pruner.should_prune()? + { + file_metrics.files_ranges_pruned_statistics.add_pruned(1); + return Ok(vec![]); + } + } + + let _metadata_timer = file_metrics.metadata_load_time.timer(); + let mut reader_metadata = + ArrowReaderMetadata::load_async(&mut async_file_reader, options.clone()) + .await?; + let num_row_groups = reader_metadata.metadata().num_row_groups(); + + // Adapt the physical schema to the file schema for pruning + let physical_file_schema = Arc::clone(reader_metadata.schema()); + let logical_file_schema = table_schema.file_schema(); + let rewriter = expr_adapter_factory.create( + Arc::clone(logical_file_schema), + Arc::clone(&physical_file_schema), + )?; + let simplifier = PhysicalExprSimplifier::new(&physical_file_schema); + + // Replace partition column references with their literal values before rewriting. + // This mirrors what `open()` does. Without this, expressions like `val != part` + // (where `part` is a partition column) would cause `rewriter.rewrite` to fail + // since the partition column is not in the logical file schema. + let literal_columns: HashMap = table_schema + .table_partition_cols() + .iter() + .zip(partitioned_file.partition_values.iter()) + .map(|(field, value)| (field.name().clone(), value.clone())) + .collect(); + + let adapted_predicate = predicate + .as_ref() + .map(|p| { + let p = if !literal_columns.is_empty() { + replace_columns_with_literals(Arc::clone(p), &literal_columns)? + } else { + Arc::clone(p) + }; + simplifier.simplify(rewriter.rewrite(p)?) + }) + .transpose()?; + + let (pruning_predicate, page_pruning_predicate) = build_pruning_predicates( + adapted_predicate.as_ref(), + &physical_file_schema, + &predicate_creation_errors, + ); + + let mut row_groups = Self::build_row_group_access_filter( + &file_name, + extensions, + num_row_groups, + reader_metadata.metadata().row_groups(), + file_range.as_ref(), + pruning_predicate + .as_deref() + .filter(|_| enable_row_group_stats_pruning) + .map(|predicate| RowGroupStatisticsPruningContext { + physical_file_schema: &physical_file_schema, + parquet_schema: reader_metadata.parquet_schema(), + predicate, + file_metrics: &file_metrics, + }), + )?; + + // Prune by limit if limit is set and order is not sensitive + if let (Some(limit), false) = (limit, preserve_order) { + row_groups.prune_by_limit( + limit, + reader_metadata.metadata().row_groups(), + &file_metrics, + ); + } + + // Bloom filter pruning: done once per file here in morselize(), so that + // open() does not repeat it for each morsel (which would cause inflated metrics + // and unnecessary work). + // + // Note: the bloom filter builder takes ownership of `async_file_reader`. + // Page index loading happens afterward using a fresh reader so that we only + // pay for the page index I/O on the row groups that survive bloom filter pruning. + if let Some(predicate) = pruning_predicate.as_deref() { + if enable_bloom_filter && !row_groups.is_empty() { + // Clone reader_metadata so it remains available for page + // index loading after this builder is dropped. + let mut builder = ParquetRecordBatchStreamBuilder::new_with_metadata( + async_file_reader, + reader_metadata.clone(), + ); + row_groups + .prune_by_bloom_filters( + &physical_file_schema, + &mut builder, + predicate, + &file_metrics, + ) + .await; + } else { + file_metrics + .row_groups_pruned_bloom_filter + .add_matched(row_groups.remaining_row_group_count()); + } + } + + // Load page index after bloom filter pruning so we skip it entirely if no + // row groups remain. Bloom filter building consumed `async_file_reader`, so + // we create a fresh reader here — reader creation is cheap (no I/O yet). + if should_enable_page_index(enable_page_index, &page_pruning_predicate) + && !row_groups.is_empty() + { + let mut fresh_reader: Box = + parquet_file_reader_factory.create_reader( + partition_index, + partitioned_file.clone(), + metadata_size_hint, + &metrics, + )?; + reader_metadata = load_page_index( + reader_metadata, + &mut fresh_reader, + options.with_page_index_policy(PageIndexPolicy::Optional), + ) + .await?; + } + + // Extract metadata after potentially loading the page index, so the cached + // metadata in each morsel includes the page index if it was loaded. + let metadata = Arc::clone(reader_metadata.metadata()); + + let mut access_plan = row_groups.build(); + + // Page pruning: done once per file here in morselize(), so that open() + // does not repeat it for each morsel. + if enable_page_index + && !access_plan.is_empty() + && let Some(p) = page_pruning_predicate + { + access_plan = p.prune_plan_with_page_index( + access_plan, + &physical_file_schema, + metadata.file_metadata().schema_descr(), + metadata.as_ref(), + &file_metrics, + ); + } + + let mut morsels = Vec::with_capacity(access_plan.len()); + for i in 0..num_row_groups { + if !access_plan.should_scan(i) { + continue; + } + let mut morsel_access_plan = ParquetAccessPlan::new_none(num_row_groups); + // Transfer the page-pruned access (Scan or Selection) for this row group + morsel_access_plan.set(i, access_plan.inner()[i].clone()); + let morsel = ParquetMorsel { + metadata: Arc::clone(&metadata), + access_plan: morsel_access_plan, + }; + let mut f = partitioned_file.clone(); + f.extensions = Some(Arc::new(morsel)); + morsels.push(f); + } + Ok(morsels) + }) + } + fn open(&self, partitioned_file: PartitionedFile) -> Result { // ----------------------------------- // Step: prepare configurations, etc. @@ -248,19 +562,27 @@ impl FileOpener for ParquetOpener { &logical_file_schema, )); - // Apply literal replacements to projection and predicate + // Apply literal replacements to projection and predicate conjuncts let mut projection = self.projection.clone(); - let mut predicate = self.predicate.clone(); + let mut predicate_conjuncts = self.predicate_conjuncts.clone(); if !literal_columns.is_empty() { projection = projection.try_map_exprs(|expr| { replace_columns_with_literals(Arc::clone(&expr), &literal_columns) })?; - predicate = predicate - .map(|p| replace_columns_with_literals(p, &literal_columns)) - .transpose()?; + if let Some(ref mut conjuncts) = predicate_conjuncts { + for (_id, expr) in conjuncts.iter_mut() { + *expr = replace_columns_with_literals( + Arc::clone(expr), + &literal_columns, + )?; + } + } } + // Build combined predicate for file-level pruning + let predicate: Option> = predicate_conjuncts + .as_ref() + .map(|c| conjunction(c.iter().map(|(_, e)| Arc::clone(e)))); - let reorder_predicates = self.reorder_filters; let pushdown_filters = self.pushdown_filters; let force_filter_selections = self.force_filter_selections; let coerce_int96 = self.coerce_int96; @@ -280,7 +602,12 @@ impl FileOpener for ParquetOpener { let reverse_row_groups = self.reverse_row_groups; let preserve_order = self.preserve_order; - + let is_morsel = partitioned_file + .extensions + .as_ref() + .map(|e| e.is::()) + .unwrap_or(false); + let selectivity_tracker = Arc::clone(&self.selectivity_tracker); Ok(Box::pin(async move { #[cfg(feature = "parquet_encryption")] let file_decryption_properties = encryption_context @@ -359,10 +686,21 @@ impl FileOpener for ParquetOpener { // Begin by loading the metadata from the underlying reader (note // the returned metadata may actually include page indexes as some // readers may return page indexes even when not requested -- for - // example when they are cached) - let mut reader_metadata = + // example when they are cached). + // If this is a morsel, we might already have the metadata cached. + let mut reader_metadata = if let Some(morsel) = partitioned_file + .extensions + .as_ref() + .and_then(|e| e.downcast_ref::()) + { + ArrowReaderMetadata::try_new( + Arc::clone(&morsel.metadata), + options.clone(), + )? + } else { ArrowReaderMetadata::load_async(&mut async_file_reader, options.clone()) - .await?; + .await? + }; // Note about schemas: we are actually dealing with **3 different schemas** here: // - The table schema as defined by the TableProvider. @@ -415,9 +753,32 @@ impl FileOpener for ParquetOpener { Arc::clone(&physical_file_schema), )?; let simplifier = PhysicalExprSimplifier::new(&physical_file_schema); - predicate = predicate - .map(|p| simplifier.simplify(rewriter.rewrite(p)?)) - .transpose()?; + + // Adapt each conjunct individually, keeping FilterIds. + // Filter out conjuncts that simplify to literal true. + if let Some(ref mut conjuncts) = predicate_conjuncts { + let mut adapted = Vec::with_capacity(conjuncts.len()); + for (id, expr) in conjuncts.drain(..) { + let rewritten = simplifier.simplify(rewriter.rewrite(expr)?)?; + // Skip conjuncts that simplified to TRUE + if let Some(lit) = rewritten + .as_any() + .downcast_ref::( + ) && let ScalarValue::Boolean(Some(true)) = lit.value() + { + continue; + } + adapted.push((id, rewritten)); + } + *conjuncts = adapted; + } + + // Build combined adapted predicate for pruning + let predicate: Option> = predicate_conjuncts + .as_ref() + .filter(|c| !c.is_empty()) + .map(|c| conjunction(c.iter().map(|(_, e)| Arc::clone(e)))); + // Adapt projections to the physical file schema as well projection = projection .try_map_exprs(|p| simplifier.simplify(rewriter.rewrite(p)?))?; @@ -432,7 +793,11 @@ impl FileOpener for ParquetOpener { // The page index is not stored inline in the parquet footer so the // code above may not have read the page index structures yet. If we // need them for reading and they aren't yet loaded, we need to load them now. - if should_enable_page_index(enable_page_index, &page_pruning_predicate) { + // For morsels, the page index was already loaded (if needed) in morselize(). + // Skip it here to avoid redundant I/O. + if should_enable_page_index(enable_page_index, &page_pruning_predicate) + && !is_morsel + { reader_metadata = load_page_index( reader_metadata, &mut async_file_reader, @@ -461,27 +826,7 @@ impl FileOpener for ParquetOpener { // --------------------------------------------------------------------- // Filter pushdown: evaluate predicates during scan - if let Some(predicate) = pushdown_filters.then_some(predicate).flatten() { - let row_filter = row_filter::build_row_filter( - &predicate, - &physical_file_schema, - builder.metadata(), - reorder_predicates, - &file_metrics, - ); - - match row_filter { - Ok(Some(filter)) => { - builder = builder.with_row_filter(filter); - } - Ok(None) => {} - Err(e) => { - debug!( - "Ignoring error building row filter for '{predicate:?}': {e}" - ); - } - }; - }; + // First, partition filters based on selectivity tracking if force_filter_selections { builder = builder.with_row_selection_policy(RowSelectionPolicy::Selectors); @@ -494,28 +839,27 @@ impl FileOpener for ParquetOpener { // Determine which row groups to actually read. The idea is to skip // as many row groups as possible based on the metadata and query let file_metadata = Arc::clone(builder.metadata()); - let predicate = pruning_predicate.as_ref().map(|p| p.as_ref()); let rg_metadata = file_metadata.row_groups(); - // track which row groups to actually read - let access_plan = - create_initial_plan(&file_name, extensions, rg_metadata.len())?; - let mut row_groups = RowGroupAccessPlanFilter::new(access_plan); - // if there is a range restricting what parts of the file to read - if let Some(range) = file_range.as_ref() { - row_groups.prune_by_range(rg_metadata, range); - } + let mut row_groups = Self::build_row_group_access_filter( + &file_name, + extensions, + rg_metadata.len(), + rg_metadata, + file_range.as_ref(), + pruning_predicate + .as_deref() + .filter(|_| enable_row_group_stats_pruning && !is_morsel) + .map(|predicate| RowGroupStatisticsPruningContext { + physical_file_schema: &physical_file_schema, + parquet_schema: builder.parquet_schema(), + predicate, + file_metrics: &file_metrics, + }), + )?; // If there is a predicate that can be evaluated against the metadata - if let Some(predicate) = predicate.as_ref() { - if enable_row_group_stats_pruning { - row_groups.prune_by_statistics( - &physical_file_schema, - builder.parquet_schema(), - rg_metadata, - predicate, - &file_metrics, - ); - } else { + if let Some(predicate) = pruning_predicate.as_deref() { + if !enable_row_group_stats_pruning { // Update metrics: statistics unavailable, so all row groups are // matched (not pruned) file_metrics @@ -523,21 +867,31 @@ impl FileOpener for ParquetOpener { .add_matched(row_groups.remaining_row_group_count()); } - if enable_bloom_filter && !row_groups.is_empty() { - row_groups - .prune_by_bloom_filters( - &physical_file_schema, - &mut builder, - predicate, - &file_metrics, - ) - .await; - } else { - // Update metrics: bloom filter unavailable, so all row groups are - // matched (not pruned) - file_metrics - .row_groups_pruned_bloom_filter - .add_matched(row_groups.remaining_row_group_count()); + // Prune by limit before bloom filter: no point reading bloom filter data + // for row groups that will be skipped by the limit anyway. + if let (Some(limit), false) = (limit, preserve_order) { + row_groups.prune_by_limit(limit, rg_metadata, &file_metrics); + } + + // For morsels, bloom filter was already applied once in morselize(). + // Skip it here to avoid double-counting metrics and redundant I/O. + if !is_morsel { + if enable_bloom_filter && !row_groups.is_empty() { + row_groups + .prune_by_bloom_filters( + &physical_file_schema, + &mut builder, + predicate, + &file_metrics, + ) + .await; + } else { + // Update metrics: bloom filter unavailable, so all row groups are + // matched (not pruned) + file_metrics + .row_groups_pruned_bloom_filter + .add_matched(row_groups.remaining_row_group_count()); + } } } else { // Update metrics: no predicate, so all row groups are matched (not pruned) @@ -550,11 +904,6 @@ impl FileOpener for ParquetOpener { .add_matched(n_remaining_row_groups); } - // Prune by limit if limit is set and limit order is not sensitive - if let (Some(limit), false) = (limit, preserve_order) { - row_groups.prune_by_limit(limit, rg_metadata, &file_metrics); - } - // -------------------------------------------------------- // Step: prune pages from the kept row groups // @@ -563,8 +912,11 @@ impl FileOpener for ParquetOpener { // be ruled using page metadata, rows from other columns // with that range can be skipped as well // -------------------------------------------------------- + // For morsels, page pruning was already applied once in morselize(). + // Skip it here to avoid double-counting metrics and redundant work. if enable_page_index && !access_plan.is_empty() + && !is_morsel && let Some(p) = page_pruning_predicate { access_plan = p.prune_plan_with_page_index( @@ -591,19 +943,89 @@ impl FileOpener for ParquetOpener { // Apply the prepared plan to the builder builder = prepared_plan.apply_to_builder(builder); - if let Some(limit) = limit { - builder = builder.with_limit(limit) - } + // Note: limit is applied later, after filter partitioning, + // because post-scan filters must run before limiting. if let Some(max_predicate_cache_size) = max_predicate_cache_size { builder = builder.with_max_predicate_cache_size(max_predicate_cache_size); } - // metrics from the arrow reader itself + // Metrics from the arrow reader itself let arrow_reader_metrics = ArrowReaderMetrics::enabled(); - let indices = projection.column_indices(); - let mask = ProjectionMask::roots(builder.parquet_schema(), indices); + let proj_cols = projection.column_indices(); + let projection_size = + row_filter::total_compressed_bytes(&proj_cols, builder.metadata()); + + let PartitionedFilters { + row_filters, + mut post_scan, + } = if pushdown_filters { + if let Some(conjuncts) = predicate_conjuncts.clone() { + if !conjuncts.is_empty() { + selectivity_tracker.partition_filters( + conjuncts, + projection_size, + &proj_cols, + builder.metadata(), + ) + } else { + PartitionedFilters::default() + } + } else { + PartitionedFilters::default() + } + } else { + PartitionedFilters::default() + }; + + // Build row filter. + if !row_filters.is_empty() { + let row_filter_result = row_filter::build_row_filter( + row_filters, + &physical_file_schema, + builder.metadata(), + projection_size, + &file_metrics, + &selectivity_tracker, + ); + + match row_filter_result { + Ok(Some(result)) => { + builder = builder.with_row_filter(result.row_filter); + // Unbuildable filters must be applied as post-scan + // to preserve correctness. + post_scan.extend(result.unbuildable_filters); + } + Ok(None) => {} + Err(e) => { + debug!("Ignoring error building row filter: {e}"); + } + }; + } + + // Include columns needed by all post-scan filters in the projection mask. + let mask = { + let mut all_indices: Vec = projection.column_indices(); + for (_, filter) in &post_scan { + for col in collect_columns(filter) { + let idx = col.index(); + if !all_indices.contains(&idx) { + all_indices.push(idx); + } + } + } + ProjectionMask::roots(builder.parquet_schema(), all_indices) + }; + + // Apply limit to the reader only when there are no post-scan filters. + // If post-scan filters exist, the limit must be enforced after filtering + // (otherwise the reader stops reading before the filter can find matches). + if post_scan.is_empty() + && let Some(limit) = limit + { + builder = builder.with_limit(limit); + } let stream = builder .with_projection(mask) @@ -616,6 +1038,7 @@ impl FileOpener for ParquetOpener { let predicate_cache_inner_records = file_metrics.predicate_cache_inner_records.clone(); let predicate_cache_records = file_metrics.predicate_cache_records.clone(); + let filter_apply_time = file_metrics.filter_apply_time.clone(); let stream_schema = Arc::clone(stream.schema()); // Check if we need to replace the schema to handle things like differing nullability or metadata. @@ -628,16 +1051,43 @@ impl FileOpener for ParquetOpener { let projection = projection .try_map_exprs(|expr| reassign_expr_columns(expr, &stream_schema))?; + // Rebase post-scan filters to stream schema + let post_scan: Vec<(crate::selectivity::FilterId, Arc)> = + post_scan + .into_iter() + .map(|(id, expr)| { + reassign_expr_columns(expr, &stream_schema).map(|e| (id, e)) + }) + .collect::>()?; + let post_scan_tracker = Arc::clone(&selectivity_tracker); + let projector = projection.make_projector(&stream_schema)?; let stream = stream.map_err(DataFusionError::from).map(move |b| { - b.and_then(|mut b| { + b.and_then(|b| { copy_arrow_reader_metrics( &arrow_reader_metrics, &predicate_cache_inner_records, &predicate_cache_records, ); - b = projector.project_batch(&b)?; + + // Apply post-scan filters BEFORE projection. + let b = if !post_scan.is_empty() { + let start = datafusion_common::instant::Instant::now(); + let filtered = apply_post_scan_filters_with_stats( + b, + &post_scan, + &post_scan_tracker, + )?; + filter_apply_time.add_elapsed(start); + filtered + } else { + b + }; + + // Then project to output columns + let b = projector.project_batch(&b)?; + if replace_schema { // Ensure the output batch has the expected schema. // This handles things like schema level and field level metadata, which may not be present @@ -662,9 +1112,8 @@ impl FileOpener for ParquetOpener { }) }); - // ---------------------------------------------------------------------- - // Step: wrap the stream so a dynamic filter can stop the file scan early - // ---------------------------------------------------------------------- + let stream = stream.boxed(); + if let Some(file_pruner) = file_pruner { Ok(EarlyStoppingStream::new( stream, @@ -673,12 +1122,69 @@ impl FileOpener for ParquetOpener { ) .boxed()) } else { - Ok(stream.boxed()) + Ok(stream) } })) } } +/// Apply post-scan filters with per-filter stats tracking for collecting filters. +/// +/// Collecting filters are evaluated individually so their selectivity and +/// evaluation time can be reported to the [`SelectivityTracker`]. Demoted +/// filters are applied as a single conjunction (no stats needed). +fn apply_post_scan_filters_with_stats( + batch: RecordBatch, + filters: &[(crate::selectivity::FilterId, Arc)], + tracker: &SelectivityTracker, +) -> Result { + use arrow::array::as_boolean_array; + use arrow::compute::{and, filter_record_batch}; + + if batch.num_rows() == 0 { + return Ok(batch); + } + + let batch_bytes = batch.get_array_memory_size() as u64; + let input_rows = batch.num_rows() as u64; + + // Start with all-true mask + let mut combined_mask: Option = None; + + // Evaluate each collecting filter individually and track stats + for &(id, ref expr) in filters { + let start = datafusion_common::instant::Instant::now(); + let result = expr.evaluate(&batch)?.into_array(batch.num_rows())?; + let bool_arr = as_boolean_array(result.as_ref()); + let nanos = start.elapsed().as_nanos() as u64; + let num_matched = bool_arr.true_count() as u64; + + // Report "other projected bytes" — batch bytes minus this filter's + // column bytes. This is consistent with what row-level filters + // report and represents the actual late-materialization savings. + let filter_bytes: u64 = collect_columns(expr) + .iter() + .map(|col| batch.column(col.index()).get_array_memory_size() as u64) + .sum(); + let other_bytes = batch_bytes.saturating_sub(filter_bytes); + tracker.update(id, num_matched, input_rows, nanos, other_bytes); + + if num_matched < input_rows { + combined_mask = Some(match combined_mask { + Some(prev) => and(&prev, bool_arr)?, + None => bool_arr.clone(), + }); + } + } + + match combined_mask { + Some(mask) => Ok(filter_record_batch(&batch, &mask)?), + None => Ok(batch), + } +} + +/// Compute the average bytes per row from parquet metadata for the projected columns. +/// /// Copies metrics from ArrowReaderMetrics (the metrics collected by the /// arrow-rs parquet reader) to the parquet file metrics for DataFusion fn copy_arrow_reader_metrics( @@ -928,6 +1434,14 @@ fn create_initial_plan( // check row group count matches the plan return Ok(access_plan.clone()); + } else if let Some(morsel) = extensions.downcast_ref::() { + let plan_len = morsel.access_plan.len(); + if plan_len != row_group_count { + return exec_err!( + "Invalid ParquetMorsel AccessPlan for {file_name}. Specified {plan_len} row groups, but file has {row_group_count}" + ); + } + return Ok(morsel.access_plan.clone()); } else { debug!("DataSourceExec Ignoring unknown extension specified for {file_name}"); } @@ -1018,7 +1532,10 @@ mod test { use std::sync::Arc; use super::{ConstantColumns, constant_columns_from_stats}; - use crate::{DefaultParquetFileReaderFactory, RowGroupAccess, opener::ParquetOpener}; + use crate::{ + DefaultParquetFileReaderFactory, RowGroupAccess, + opener::{ParquetMorsel, ParquetOpener}, + }; use arrow::datatypes::{DataType, Field, Schema, SchemaRef}; use bytes::{BufMut, BytesMut}; use datafusion_common::{ @@ -1036,7 +1553,7 @@ mod test { use datafusion_physical_expr_adapter::{ DefaultPhysicalExprAdapterFactory, replace_columns_with_literals, }; - use datafusion_physical_plan::metrics::ExecutionPlanMetricsSet; + use datafusion_physical_plan::metrics::{ExecutionPlanMetricsSet, MetricValue}; use futures::{Stream, StreamExt}; use object_store::{ObjectStore, ObjectStoreExt, memory::InMemory, path::Path}; use parquet::arrow::ArrowWriter; @@ -1052,11 +1569,11 @@ mod test { projection: Option, batch_size: usize, limit: Option, - predicate: Option>, + predicate_conjuncts: + Option)>>, metadata_size_hint: Option, metrics: ExecutionPlanMetricsSet, pushdown_filters: bool, - reorder_filters: bool, force_filter_selections: bool, enable_page_index: bool, enable_bloom_filter: bool, @@ -1078,11 +1595,10 @@ mod test { projection: None, batch_size: 1024, limit: None, - predicate: None, + predicate_conjuncts: None, metadata_size_hint: None, metrics: ExecutionPlanMetricsSet::new(), pushdown_filters: false, - reorder_filters: false, force_filter_selections: false, enable_page_index: false, enable_bloom_filter: false, @@ -1120,7 +1636,14 @@ mod test { /// Set the predicate. fn with_predicate(mut self, predicate: Arc) -> Self { - self.predicate = Some(predicate); + use datafusion_physical_expr::split_conjunction; + let conjuncts: Vec<(crate::selectivity::FilterId, Arc)> = + split_conjunction(&predicate) + .into_iter() + .enumerate() + .map(|(id, expr)| (id, Arc::clone(expr))) + .collect(); + self.predicate_conjuncts = Some(conjuncts); self } @@ -1130,12 +1653,6 @@ mod test { self } - /// Enable filter reordering. - fn with_reorder_filters(mut self, enable: bool) -> Self { - self.reorder_filters = enable; - self - } - /// Enable row group stats pruning. fn with_row_group_stats_pruning(mut self, enable: bool) -> Self { self.enable_row_group_stats_pruning = enable; @@ -1177,7 +1694,7 @@ mod test { projection, batch_size: self.batch_size, limit: self.limit, - predicate: self.predicate, + predicate_conjuncts: self.predicate_conjuncts, table_schema, metadata_size_hint: self.metadata_size_hint, metrics: self.metrics, @@ -1185,7 +1702,6 @@ mod test { DefaultParquetFileReaderFactory::new(store), ), pushdown_filters: self.pushdown_filters, - reorder_filters: self.reorder_filters, force_filter_selections: self.force_filter_selections, enable_page_index: self.enable_page_index, enable_bloom_filter: self.enable_bloom_filter, @@ -1199,6 +1715,13 @@ mod test { max_predicate_cache_size: self.max_predicate_cache_size, reverse_row_groups: self.reverse_row_groups, preserve_order: self.preserve_order, + // Tests use INFINITY to push all filters as row filters + selectivity_tracker: Arc::new( + crate::selectivity::TrackerConfig::new() + .with_byte_ratio_threshold(f64::INFINITY) + .with_min_bytes_per_sec(0.0) + .build(), + ), } } } @@ -1366,6 +1889,19 @@ mod test { )) } + fn get_pruning_metric( + metrics: &ExecutionPlanMetricsSet, + metric_name: &str, + ) -> (usize, usize) { + match metrics.clone_inner().sum_by_name(metric_name) { + Some(MetricValue::PruningMetrics { + pruning_metrics, .. + }) => (pruning_metrics.pruned(), pruning_metrics.matched()), + Some(_) => panic!("Metric '{metric_name}' is not a pruning metric"), + None => panic!("Metric '{metric_name}' not found"), + } + } + #[tokio::test] async fn test_prune_on_statistics() { let store = Arc::new(InMemory::new()) as Arc; @@ -1596,7 +2132,6 @@ mod test { .with_projection_indices(&[0]) .with_predicate(predicate) .with_pushdown_filters(true) // note that this is true! - .with_reorder_filters(true) .build() }; @@ -1627,7 +2162,10 @@ mod test { assert_eq!(num_batches, 1); assert_eq!(num_rows, 1); - // Filter should not match the partition value or the data value + // Filter should not match the partition value or the data value. + // With adaptive selectivity tracking, unknown filters are pushed down + // as row filters initially. The row filter prunes all rows during decoding, + // resulting in no batches being returned. let expr = col("part").eq(lit(2)).or(col("a").eq(lit(3))); let predicate = logical2physical(&expr, &table_schema); let opener = make_opener(predicate); @@ -2005,4 +2543,115 @@ mod test { "Reverse scan with non-contiguous row groups should correctly map RowSelection" ); } + + #[tokio::test] + async fn test_open_and_morselize_are_equivalent_except_for_morsels() { + use parquet::file::properties::WriterProperties; + + let store = Arc::new(InMemory::new()) as Arc; + + let batch1 = record_batch!(("a", Int32, vec![Some(1), Some(2)])).unwrap(); + let batch2 = record_batch!(("a", Int32, vec![Some(10), Some(11)])).unwrap(); + let batch3 = record_batch!(("a", Int32, vec![Some(20), Some(21)])).unwrap(); + + let props = WriterProperties::builder() + .set_max_row_group_row_count(Some(2)) + .build(); + + let data_len = write_parquet_batches( + Arc::clone(&store), + "test.parquet", + vec![batch1.clone(), batch2.clone(), batch3.clone()], + Some(props), + ) + .await; + + let schema = batch1.schema(); + let file = PartitionedFile::new( + "test.parquet".to_string(), + u64::try_from(data_len).unwrap(), + ); + + for enable_row_group_stats_pruning in [false, true] { + let expr = col("a").gt(lit(5)).and(col("a").lt(lit(20))); + let predicate = logical2physical(&expr, &schema); + + let baseline_opener = ParquetOpenerBuilder::new() + .with_store(Arc::clone(&store)) + .with_schema(Arc::clone(&schema)) + .with_projection_indices(&[0]) + .with_predicate(Arc::clone(&predicate)) + .with_row_group_stats_pruning(enable_row_group_stats_pruning) + .build(); + + // Baseline: regular open path + let stream = baseline_opener.open(file.clone()).unwrap().await.unwrap(); + let baseline_values = collect_int32_values(stream).await; + let baseline_stats_metrics = get_pruning_metric( + &baseline_opener.metrics, + "row_groups_pruned_statistics", + ); + let baseline_bloom_metrics = get_pruning_metric( + &baseline_opener.metrics, + "row_groups_pruned_bloom_filter", + ); + + let morsel_opener = ParquetOpenerBuilder::new() + .with_store(Arc::clone(&store)) + .with_schema(Arc::clone(&schema)) + .with_projection_indices(&[0]) + .with_predicate(predicate) + .with_row_group_stats_pruning(enable_row_group_stats_pruning) + .build(); + + // Morsel path: split into morsels and open each morsel + let morsels = morsel_opener.morselize(file.clone()).await.unwrap(); + assert!( + !morsels.is_empty(), + "Expected at least one morsel for the selected row groups" + ); + + let mut morsel_values = vec![]; + for morsel_file in morsels { + let morsel = morsel_file + .extensions + .as_ref() + .and_then(|ext| ext.downcast_ref::()) + .expect("morselized file should carry ParquetMorsel extension"); + + assert_eq!( + morsel.access_plan.row_group_indexes().len(), + 1, + "each morsel should scan exactly one row group" + ); + + let stream = morsel_opener.open(morsel_file).unwrap().await.unwrap(); + morsel_values.extend(collect_int32_values(stream).await); + } + + let morsel_stats_metrics = get_pruning_metric( + &morsel_opener.metrics, + "row_groups_pruned_statistics", + ); + let morsel_bloom_metrics = get_pruning_metric( + &morsel_opener.metrics, + "row_groups_pruned_bloom_filter", + ); + + assert_eq!( + baseline_values, morsel_values, + "open and morselize paths should scan equivalent data; morselize only changes work granularity" + ); + + assert_eq!( + baseline_stats_metrics, morsel_stats_metrics, + "row_groups_pruned_statistics should be equivalent for open vs morselize path (enable_row_group_stats_pruning={enable_row_group_stats_pruning})" + ); + + assert_eq!( + baseline_bloom_metrics, morsel_bloom_metrics, + "row_groups_pruned_bloom_filter should be equivalent for open vs morselize path (enable_row_group_stats_pruning={enable_row_group_stats_pruning})" + ); + } + } } diff --git a/datafusion/datasource-parquet/src/row_filter.rs b/datafusion/datasource-parquet/src/row_filter.rs index 2924208c5bd99..e8b07d176ec99 100644 --- a/datafusion/datasource-parquet/src/row_filter.rs +++ b/datafusion/datasource-parquet/src/row_filter.rs @@ -64,7 +64,6 @@ //! columns and other nested projections that are not explicitly supported will //! continue to be evaluated after the batches are materialized. -use std::cmp::Ordering; use std::collections::BTreeSet; use std::sync::Arc; @@ -79,15 +78,26 @@ use parquet::schema::types::SchemaDescriptor; use datafusion_common::Result; use datafusion_common::cast::as_boolean_array; +use datafusion_common::instant::Instant; use datafusion_common::tree_node::{TreeNode, TreeNodeRecursion, TreeNodeVisitor}; +use datafusion_physical_expr::PhysicalExpr; use datafusion_physical_expr::expressions::Column; use datafusion_physical_expr::utils::reassign_expr_columns; -use datafusion_physical_expr::{PhysicalExpr, split_conjunction}; use datafusion_physical_plan::metrics; use super::ParquetFileMetrics; use super::supported_predicates::supports_list_predicates; +use crate::selectivity::{FilterId, SelectivityTracker}; + +/// Result of building a row filter, containing both the filter and per-expression metrics. +pub struct RowFilterWithMetrics { + /// The row filter to apply during parquet decoding + pub row_filter: RowFilter, + /// Filter expressions that could not be built into row filters and must be + /// applied as post-scan filters to preserve correctness. + pub unbuildable_filters: Vec<(FilterId, Arc)>, +} /// A "compiled" predicate passed to `ParquetRecordBatchStream` to perform /// row-level filtering during parquet decoding. @@ -102,12 +112,19 @@ use super::supported_predicates::supports_list_predicates; /// supported predicates (such as `array_has_all` or NULL checks). Struct /// columns are still evaluated after decoding. #[derive(Debug)] -pub(crate) struct DatafusionArrowPredicate { +struct DatafusionArrowPredicate { /// the filter expression physical_expr: Arc, /// Path to the leaf columns in the parquet schema required to evaluate the /// expression projection_mask: ProjectionMask, + /// Unique identifier for this filter + filter_id: FilterId, + /// Tracker for dynamic filter effectiveness + selectivity_tracker: Arc, + /// Estimated compressed bytes per row for columns NOT used by this filter + /// but in the projection — the bytes late materialization actually saves. + other_projected_bytes_per_row: f64, /// how many rows were filtered out by this predicate rows_pruned: metrics::Count, /// how many rows passed this predicate @@ -118,9 +135,13 @@ pub(crate) struct DatafusionArrowPredicate { impl DatafusionArrowPredicate { /// Create a new `DatafusionArrowPredicate` from a `FilterCandidate` - pub fn try_new( + #[expect(clippy::too_many_arguments)] + fn try_new( candidate: FilterCandidate, metadata: &ParquetMetaData, + projection_compressed_bytes: usize, + filter_id: FilterId, + selectivity_tracker: Arc, rows_pruned: metrics::Count, rows_matched: metrics::Count, time: metrics::Time, @@ -128,6 +149,20 @@ impl DatafusionArrowPredicate { let physical_expr = reassign_expr_columns(candidate.expr, &candidate.filter_schema)?; + // Compute bytes-per-row for projected columns NOT in this filter. + // This represents the actual savings from late materialization: + // for each pruned row we avoid decoding these other columns. + let filter_col_indices: Vec = candidate.projection.leaf_indices.to_vec(); + let filter_compressed_bytes = + total_compressed_bytes(&filter_col_indices, metadata); + let total_rows: i64 = metadata.row_groups().iter().map(|rg| rg.num_rows()).sum(); + let other_projected_bytes_per_row = if total_rows > 0 { + (projection_compressed_bytes.saturating_sub(filter_compressed_bytes)) as f64 + / total_rows as f64 + } else { + 0.0 + }; + Ok(Self { physical_expr, // Use leaf indices: when nested columns are involved, we must specify @@ -137,6 +172,9 @@ impl DatafusionArrowPredicate { metadata.file_metadata().schema_descr(), candidate.projection.leaf_indices.iter().copied(), ), + filter_id, + selectivity_tracker, + other_projected_bytes_per_row, rows_pruned, rows_matched, time, @@ -152,6 +190,12 @@ impl ArrowPredicate for DatafusionArrowPredicate { fn evaluate(&mut self, batch: RecordBatch) -> ArrowResult { // scoped timer updates on drop let mut timer = self.time.timer(); + let input_rows = batch.num_rows() as u64; + // Report "other projected bytes" — the bytes of non-filter columns + // that late materialization saves by pruning rows. This makes the + // effectiveness metric consistent with post-scan reporting. + let other_bytes = (self.other_projected_bytes_per_row * input_rows as f64) as u64; + let start = Instant::now(); self.physical_expr .evaluate(&batch) @@ -160,9 +204,23 @@ impl ArrowPredicate for DatafusionArrowPredicate { let bool_arr = as_boolean_array(&array)?.clone(); let num_matched = bool_arr.true_count(); let num_pruned = bool_arr.len() - num_matched; + self.rows_pruned.add(num_pruned); self.rows_matched.add(num_matched); + timer.stop(); + + // Report effectiveness to SelectivityTracker using other-column + // bytes (the actual savings from late materialization). + let nanos = start.elapsed().as_nanos() as u64; + self.selectivity_tracker.update( + self.filter_id, + num_matched as u64, + input_rows, + nanos, + other_bytes, + ); + Ok(bool_arr) }) .map_err(|e| { @@ -181,13 +239,6 @@ impl ArrowPredicate for DatafusionArrowPredicate { /// See the module level documentation for more information. pub(crate) struct FilterCandidate { expr: Arc, - /// Estimate for the total number of bytes that will need to be processed - /// to evaluate this filter. This is used to estimate the cost of evaluating - /// the filter and to order the filters when `reorder_predicates` is true. - /// This is generated by summing the compressed size of all columns that the filter references. - required_bytes: usize, - /// Can this filter use an index (e.g. a page index) to prune rows? - can_use_index: bool, /// Column indices into the parquet file schema required to evaluate this filter. projection: LeafProjection, /// The Arrow schema containing only the columns required by this filter, @@ -250,13 +301,8 @@ impl FilterCandidateBuilder { let projected_schema = Arc::new(self.file_schema.project(&root_indices)?); - let required_bytes = size_of_columns(&leaf_indices, metadata)?; - let can_use_index = columns_sorted(&leaf_indices, metadata)?; - Ok(Some(FilterCandidate { expr: self.expr, - required_bytes, - can_use_index, projection: LeafProjection { leaf_indices }, filter_schema: projected_schema, })) @@ -530,111 +576,65 @@ pub fn can_expr_be_pushed_down_with_schemas( } } -/// Calculate the total compressed size of all leaf columns required for -/// predicate `Expr`. -/// -/// This value represents the total amount of IO required to evaluate the -/// predicate. -fn size_of_columns(columns: &[usize], metadata: &ParquetMetaData) -> Result { - let mut total_size = 0; - let row_groups = metadata.row_groups(); - for idx in columns { - for rg in row_groups.iter() { - total_size += rg.column(*idx).compressed_size() as usize; - } - } - - Ok(total_size) -} - -/// For a given set of `Column`s required for predicate `Expr` determine whether -/// all columns are sorted. -/// -/// Sorted columns may be queried more efficiently in the presence of -/// a PageIndex. -fn columns_sorted(_columns: &[usize], _metadata: &ParquetMetaData) -> Result { - // TODO How do we know this? - Ok(false) -} - -/// Build a [`RowFilter`] from the given predicate expression if possible. +/// Build a [`RowFilter`] from the given predicate expressions if possible. /// /// # Arguments -/// * `expr` - The filter predicate, already adapted to reference columns in `file_schema` +/// * `exprs` - Filter predicates with their IDs, already split and ordered by SelectivityTracker /// * `file_schema` - The Arrow schema of the parquet file (the result of converting /// the parquet schema to Arrow, potentially with type coercions applied) /// * `metadata` - Parquet file metadata used for cost estimation -/// * `reorder_predicates` - If true, reorder predicates to minimize I/O /// * `file_metrics` - Metrics for tracking filter performance +/// * `selectivity_tracker` - Tracker for dynamic filter effectiveness /// /// # Returns -/// * `Ok(Some(row_filter))` if the expression can be used as a RowFilter -/// * `Ok(None)` if the expression cannot be used as a RowFilter +/// * `Ok(Some(row_filter_with_metrics))` containing the row filter and unbuildable filters +/// * `Ok(None)` if no filters can be built /// * `Err(e)` if an error occurs while building the filter -/// -/// Note: The returned `RowFilter` may not contain all conjuncts from the original -/// expression. Conjuncts that cannot be evaluated as an `ArrowPredicate` are ignored. -/// -/// For example, if the expression is `a = 1 AND b = 2 AND c = 3` and `b = 2` -/// cannot be evaluated for some reason, the returned `RowFilter` will contain -/// only `a = 1` and `c = 3`. pub fn build_row_filter( - expr: &Arc, + exprs: Vec<(FilterId, Arc)>, file_schema: &SchemaRef, metadata: &ParquetMetaData, - reorder_predicates: bool, + projection_compressed_bytes: usize, file_metrics: &ParquetFileMetrics, -) -> Result> { + selectivity_tracker: &Arc, +) -> Result> { let rows_pruned = &file_metrics.pushdown_rows_pruned; let rows_matched = &file_metrics.pushdown_rows_matched; let time = &file_metrics.row_pushdown_eval_time; - // Split into conjuncts: - // `a = 1 AND b = 2 AND c = 3` -> [`a = 1`, `b = 2`, `c = 3`] - let predicates = split_conjunction(expr); + let mut unbuildable_filters = Vec::new(); - // Determine which conjuncts can be evaluated as ArrowPredicates, if any - let mut candidates: Vec = predicates - .into_iter() - .map(|expr| { - FilterCandidateBuilder::new(Arc::clone(expr), Arc::clone(file_schema)) - .build(metadata) - }) - .collect::, _>>()? - .into_iter() - .flatten() - .collect(); - - // no candidates - if candidates.is_empty() { - return Ok(None); + // Build FilterCandidates (same pattern as main, but with FilterId tracking) + let mut candidates: Vec<(FilterId, FilterCandidate)> = Vec::new(); + for (id, expr) in exprs { + match FilterCandidateBuilder::new(Arc::clone(&expr), Arc::clone(file_schema)) + .build(metadata)? + { + Some(candidate) => candidates.push((id, candidate)), + None => unbuildable_filters.push((id, expr)), + } } - if reorder_predicates { - candidates.sort_unstable_by(|c1, c2| { - match c1.can_use_index.cmp(&c2.can_use_index) { - Ordering::Equal => c1.required_bytes.cmp(&c2.required_bytes), - ord => ord, - } - }); + // No candidates - return early + if candidates.is_empty() { + if unbuildable_filters.is_empty() { + return Ok(None); + } + return Ok(Some(RowFilterWithMetrics { + row_filter: RowFilter::new(vec![]), + unbuildable_filters, + })); } - // To avoid double-counting metrics when multiple predicates are used: - // - All predicates should count rows_pruned (cumulative pruned rows) - // - Only the last predicate should count rows_matched (final result) - // This ensures: rows_matched + rows_pruned = total rows processed - let total_candidates = candidates.len(); + // NO REORDERING - filters are already ordered by SelectivityTracker - candidates + // Build predicates (same pattern as main's enumerate logic) + let total = candidates.len(); + let predicates = candidates .into_iter() .enumerate() - .map(|(idx, candidate)| { - let is_last = idx == total_candidates - 1; - - // All predicates share the pruned counter (cumulative) - let predicate_rows_pruned = rows_pruned.clone(); - - // Only the last predicate tracks matched rows (final result) + .map(|(idx, (filter_id, candidate))| { + let is_last = idx == total - 1; let predicate_rows_matched = if is_last { rows_matched.clone() } else { @@ -644,14 +644,37 @@ pub fn build_row_filter( DatafusionArrowPredicate::try_new( candidate, metadata, - predicate_rows_pruned, + projection_compressed_bytes, + filter_id, + Arc::clone(selectivity_tracker), + rows_pruned.clone(), predicate_rows_matched, time.clone(), ) - .map(|pred| Box::new(pred) as _) + .map(|pred| Box::new(pred) as Box) }) - .collect::, _>>() - .map(|filters| Some(RowFilter::new(filters))) + .collect::>>()?; + + Ok(Some(RowFilterWithMetrics { + row_filter: RowFilter::new(predicates), + unbuildable_filters, + })) +} + +/// Compute the total compressed bytes for a set of column indices across all row groups. +pub(crate) fn total_compressed_bytes( + column_indices: &[usize], + metadata: &ParquetMetaData, +) -> usize { + let mut total = 0usize; + for rg in metadata.row_groups() { + for &idx in column_indices { + if idx < rg.num_columns() { + total += rg.column(idx).compressed_size() as usize; + } + } + } + total } #[cfg(test)] @@ -747,9 +770,13 @@ mod test { .expect("building candidate") .expect("candidate expected"); + let selectivity_tracker = Arc::new(SelectivityTracker::new()); let mut row_filter = DatafusionArrowPredicate::try_new( candidate, &metadata, + 0, // projection_compressed_bytes (not relevant for this test) + 0, // filter_id + selectivity_tracker, Count::new(), Count::new(), Time::new(), @@ -787,9 +814,13 @@ mod test { .expect("building candidate") .expect("candidate expected"); + let selectivity_tracker = Arc::new(SelectivityTracker::new()); let mut row_filter = DatafusionArrowPredicate::try_new( candidate, &metadata, + 0, // projection_compressed_bytes + 0, // filter_id + selectivity_tracker, Count::new(), Count::new(), Time::new(), @@ -937,13 +968,25 @@ mod test { let file_metrics = ParquetFileMetrics::new(0, &format!("{func_name}.parquet"), &metrics); - let row_filter = - build_row_filter(&expr, &file_schema, &metadata, false, &file_metrics) - .expect("building row filter") - .expect("row filter should exist"); + let selectivity_tracker = Arc::new(SelectivityTracker::new()); + let exprs = vec![(0, expr)]; // Single filter with ID 0 + let projection_bytes = total_compressed_bytes( + &(0..file_schema.fields().len()).collect::>(), + &metadata, + ); + let row_filter_with_metrics = build_row_filter( + exprs, + &file_schema, + &metadata, + projection_bytes, + &file_metrics, + &selectivity_tracker, + ) + .expect("building row filter") + .expect("row filter should exist"); let reader = parquet_reader_builder - .with_row_filter(row_filter) + .with_row_filter(row_filter_with_metrics.row_filter) .build() .expect("build reader"); diff --git a/datafusion/datasource-parquet/src/selectivity.rs b/datafusion/datasource-parquet/src/selectivity.rs new file mode 100644 index 0000000000000..de0434831752f --- /dev/null +++ b/datafusion/datasource-parquet/src/selectivity.rs @@ -0,0 +1,1672 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Adaptive filter selectivity tracking for Parquet row filters. +//! +//! See [`SelectivityTracker`] for the main entry point, `FilterState` for the +//! per-filter lifecycle, `PartitionedFilters` for the output consumed by +//! `ParquetOpener::open`, and [`FilterId`] for stable filter identification. + +use log::debug; +use parking_lot::RwLock; +use parquet::file::metadata::ParquetMetaData; +use std::collections::HashMap; +use std::sync::Arc; + +use datafusion_physical_expr::utils::collect_columns; +use datafusion_physical_expr_common::physical_expr::{ + OptionalFilterPhysicalExpr, PhysicalExpr, snapshot_generation, +}; + +/// Stable identifier for a filter conjunct, assigned by `ParquetSource::with_predicate`. +pub type FilterId = usize; + +/// Per-filter lifecycle state in the adaptive filter system. +/// +/// State transitions: +/// - **(unseen)** → [`RowFilter`](Self::RowFilter) or [`PostScan`](Self::PostScan) +/// on first encounter in [`SelectivityTracker::partition_filters`]. +/// - [`PostScan`](Self::PostScan) → [`RowFilter`](Self::RowFilter) when +/// effectiveness ≥ `min_bytes_per_sec` and enough rows have been observed. +/// - [`RowFilter`](Self::RowFilter) → [`PostScan`](Self::PostScan) when +/// effectiveness is below threshold (mandatory filter). +/// - [`RowFilter`](Self::RowFilter) → [`Dropped`](Self::Dropped) when +/// effectiveness is below threshold and the filter is optional +/// ([`OptionalFilterPhysicalExpr`]). +/// - [`RowFilter`](Self::RowFilter) → [`PostScan`](Self::PostScan)/[`Dropped`](Self::Dropped) +/// on periodic re-evaluation if effectiveness drops below threshold after +/// CI upper bound drops below threshold. +/// - **Any state** → re-evaluated when a dynamic filter's +/// `snapshot_generation` changes. +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) enum FilterState { + /// Currently a row filter. + RowFilter, + /// Currently a post-scan filter. + PostScan, + /// Dropped entirely (insufficient throughput and optional). + Dropped, +} + +/// Result of partitioning filters into row filters vs post-scan. +/// +/// Produced by [`SelectivityTracker::partition_filters`], consumed by +/// `ParquetOpener::open` to build row-level predicates and post-scan filters. +/// +/// Filters are partitioned based on their effectiveness threshold. +#[derive(Debug, Clone, Default)] +pub(crate) struct PartitionedFilters { + /// Filters promoted past collection — individual chained ArrowPredicates + pub(crate) row_filters: Vec<(FilterId, Arc)>, + /// Filters demoted to post-scan (fast path only) + pub(crate) post_scan: Vec<(FilterId, Arc)>, +} + +/// Tracks selectivity statistics for a single filter expression. +#[derive(Debug, Clone, Default, Copy, PartialEq)] +struct SelectivityStats { + /// Number of rows that matched (passed) the filter + rows_matched: u64, + /// Total number of rows evaluated + rows_total: u64, + /// Cumulative evaluation time in nanoseconds + eval_nanos: u64, + /// Cumulative bytes across batches this filter has been evaluated on + bytes_seen: u64, + /// Welford's online algorithm: number of per-batch effectiveness samples + sample_count: u64, + /// Welford's online algorithm: running mean of per-batch effectiveness + eff_mean: f64, + /// Welford's online algorithm: running sum of squared deviations (M2) + eff_m2: f64, +} + +impl SelectivityStats { + /// Returns the effectiveness as an opaque ordering score (higher = run first). + /// + /// Currently computed as bytes/sec throughput using self-contained stats. + /// Callers should not assume the unit. + fn effectiveness(&self) -> Option { + if self.rows_total == 0 || self.eval_nanos == 0 || self.bytes_seen == 0 { + return None; + } + let rows_pruned = self.rows_total - self.rows_matched; + let bytes_per_row = self.bytes_seen as f64 / self.rows_total as f64; + let bytes_saved = rows_pruned as f64 * bytes_per_row; + Some(bytes_saved * 1_000_000_000.0 / self.eval_nanos as f64) + } + + /// Returns the lower bound of a confidence interval on mean effectiveness. + /// + /// Uses Welford's online variance to compute a one-sided CI: + /// `mean - z * stderr`. Returns `None` if fewer than 2 samples. + fn confidence_lower_bound(&self, confidence_z: f64) -> Option { + if self.sample_count < 2 { + return None; + } + let variance = self.eff_m2 / (self.sample_count - 1) as f64; + let stderr = (variance / self.sample_count as f64).sqrt(); + Some(self.eff_mean - confidence_z * stderr) + } + + /// Returns the upper bound of a confidence interval on mean effectiveness. + /// + /// Uses Welford's online variance: `mean + z * stderr`. + /// Returns `None` if fewer than 2 samples. + fn confidence_upper_bound(&self, confidence_z: f64) -> Option { + if self.sample_count < 2 { + return None; + } + let variance = self.eff_m2 / (self.sample_count - 1) as f64; + let stderr = (variance / self.sample_count as f64).sqrt(); + Some(self.eff_mean + confidence_z * stderr) + } + + /// Update stats with new observations. + fn update(&mut self, matched: u64, total: u64, eval_nanos: u64, batch_bytes: u64) { + self.rows_matched += matched; + self.rows_total += total; + self.eval_nanos += eval_nanos; + self.bytes_seen += batch_bytes; + + // Feed Welford's algorithm with per-batch effectiveness + if total > 0 && eval_nanos > 0 && batch_bytes > 0 { + let rows_pruned = total - matched; + let bytes_per_row = batch_bytes as f64 / total as f64; + let batch_eff = + (rows_pruned as f64 * bytes_per_row) * 1e9 / eval_nanos as f64; + + self.sample_count += 1; + let delta = batch_eff - self.eff_mean; + self.eff_mean += delta / self.sample_count as f64; + let delta2 = batch_eff - self.eff_mean; + self.eff_m2 += delta * delta2; + } + } +} + +/// Immutable configuration for a [`SelectivityTracker`]. +/// +/// Use the builder methods to customise, then call [`build()`](TrackerConfig::build) +/// to produce a ready-to-use tracker. +pub(crate) struct TrackerConfig { + /// Minimum bytes/sec throughput for promoting a filter (default: INFINITY = disabled). + pub min_bytes_per_sec: f64, + /// Byte-ratio threshold for placing collecting filters at row-level vs post-scan. + /// This ratio represents the estimated bytes needed to evaluate the filter across the entire file divided by the total bytes in the projection. + /// A lower ratio means the filter is cheaper to evaluate and should be placed at row-level immediately, while a higher ratio means the filter is more expensive and should start as post-scan. + /// A value of ~1 means the filter is the same size as the entire projection at which point evaluating the filter at row-level may not be worth it without evidence of high effectiveness. + /// A value of ~0 means the filter is probably very cheap to evaluate relative to the projection. + /// Default is 0.15 (filters estimated to require more than 15% of the projection bytes will start as post-scan). + pub byte_ratio_threshold: f64, + /// Z-score for confidence intervals on filter effectiveness. + /// Lower values (e.g. 1.0 or 0.0) will make the tracker more aggressive about promotion/demotion based on limited data. + /// Higher values (e.g. 3.0) will require more confidence before changing filter states. + /// Default is 2.0, corresponding to ~97.5% one-sided confidence. + /// Set to <= 0.0 to disable confidence intervals and promote/demote based on point estimates alone (not recommended). + /// Set to INFINITY to disable promotion entirely (overrides `min_bytes_per_sec`). + pub confidence_z: f64, +} + +impl TrackerConfig { + pub fn new() -> Self { + Self { + min_bytes_per_sec: f64::INFINITY, + byte_ratio_threshold: 0.05, + confidence_z: 2.0, + } + } + + pub fn with_min_bytes_per_sec(mut self, v: f64) -> Self { + self.min_bytes_per_sec = v; + self + } + + pub fn with_byte_ratio_threshold(mut self, v: f64) -> Self { + self.byte_ratio_threshold = v; + self + } + + pub fn with_confidence_z(mut self, v: f64) -> Self { + self.confidence_z = v; + self + } + + pub fn build(self) -> SelectivityTracker { + SelectivityTracker { + config: self, + inner: RwLock::new(SelectivityTrackerInner::new()), + } + } +} + +impl Default for TrackerConfig { + fn default() -> Self { + Self::new() + } +} + +/// Cross-file adaptive system that measures filter effectiveness and decides +/// which filters are promoted to row-level predicates (pushed into the Parquet +/// reader) vs. applied post-scan (demoted) or dropped entirely. +/// +/// The `RwLock` is **private** — external callers cannot hold the guard across +/// expensive work. All lock-holding code paths are auditable in this file. +/// +/// # Filter state machine +/// +/// ```text +/// ┌─────────┐ +/// │ New │ +/// └─────────┘ +/// │ +/// ▼ +/// ┌────────────────────────┐ +/// │ Estimated Cost │ +/// │Bytes needed for filter │ +/// └────────────────────────┘ +/// │ +/// ┌──────────────────┴──────────────────┐ +/// ┌────────▼────────┐ ┌────────▼────────┐ +/// │ Post-scan │ │ Row filter │ +/// │ │ │ │ +/// └─────────────────┘ └─────────────────┘ +/// │ │ +/// ▼ ▼ +/// ┌─────────────────┐ ┌─────────────────┐ +/// │ Effectiveness │ │ Effectiveness │ +/// │ Bytes pruned │ │ Bytes pruned │ +/// │ per │ │ per │ +/// │Second of compute│ │Second of compute│ +/// └─────────────────┘ └─────────────────┘ +/// │ │ +/// └──────────────────┬──────────────────┘ +/// ▼ +/// ┌───────────────────────────────────────────────┐ +/// │ New Scan │ +/// │ Move filters based on effectiveness. │ +/// │ Promote (move post-scan -> row filter). │ +/// │ Demote (move row-filter -> post-scan). │ +/// │ Disable (for optional filters; either row │ +/// │ filter or disabled). │ +/// └───────────────────────────────────────────────┘ +/// │ +/// ┌──────────────────┴──────────────────┐ +/// ┌────────▼────────┐ ┌────────▼────────┐ +/// │ Post-scan │ │ Row filter │ +/// │ │ │ │ +/// └─────────────────┘ └─────────────────┘ +/// ``` +/// +/// See `TrackerConfig` for configuration knobs. +pub struct SelectivityTracker { + config: TrackerConfig, + inner: RwLock, +} + +impl std::fmt::Debug for SelectivityTracker { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SelectivityTracker") + .field("config.min_bytes_per_sec", &self.config.min_bytes_per_sec) + .finish() + } +} + +impl Default for SelectivityTracker { + fn default() -> Self { + Self::new() + } +} + +impl SelectivityTracker { + /// Create a new tracker with default settings (feature disabled). + pub fn new() -> Self { + TrackerConfig::new().build() + } + + /// Update stats for a filter after processing a batch. + /// + /// Acquires and releases the write lock in bounded time. + /// Debug-logs lock wait times > 100μs **after** dropping the lock. + pub(crate) fn update( + &self, + id: FilterId, + matched: u64, + total: u64, + eval_nanos: u64, + batch_bytes: u64, + ) { + self.inner + .write() + .update(id, matched, total, eval_nanos, batch_bytes); + } + + /// Partition filters into collecting / promoted / post-scan. + pub(crate) fn partition_filters( + &self, + filters: Vec<(FilterId, Arc)>, + projection_scan_size: usize, + projection_columns: &[usize], + metadata: &ParquetMetaData, + ) -> PartitionedFilters { + self.inner.write().partition_filters( + filters, + projection_scan_size, + projection_columns, + metadata, + &self.config, + ) + } +} + +/// Mutable state guarded by the `RwLock` inside [`SelectivityTracker`]. +#[derive(Debug)] +struct SelectivityTrackerInner { + /// Per-filter effectiveness statistics, keyed by FilterId + stats: HashMap, + /// Per-filter lifecycle state + filter_states: HashMap, + /// Snapshot generation for each filter (for detecting dynamic filter updates) + snapshot_generations: HashMap, +} + +impl SelectivityTrackerInner { + fn new() -> Self { + Self { + stats: HashMap::new(), + filter_states: HashMap::new(), + snapshot_generations: HashMap::new(), + } + } + + /// Check and update the snapshot generation for a filter. + fn note_generation(&mut self, id: FilterId, generation: u64) { + if generation == 0 { + return; + } + match self.snapshot_generations.get(&id) { + Some(&prev_generation) if prev_generation == generation => {} + Some(_) => { + let current_state = self.filter_states.get(&id).copied(); + // Always reset stats since selectivity changed with new generation. + self.stats.remove(&id); + self.snapshot_generations.insert(id, generation); + + // Optional/dynamic filters only get more selective over time + // (hash join build side accumulates more values). So if the + // filter was already working (RowFilter or PostScan), preserve + // its state. Only un-drop Dropped filters back to PostScan + // so they get another chance with the new selectivity. + if current_state == Some(FilterState::Dropped) { + debug!("FilterId {id} generation changed, un-dropping to PostScan"); + self.filter_states.insert(id, FilterState::PostScan); + } else { + debug!( + "FilterId {id} generation changed, resetting stats but preserving state {current_state:?}" + ); + } + } + None => { + self.snapshot_generations.insert(id, generation); + } + } + } + + /// Get the effectiveness for a filter by ID. + fn get_effectiveness_by_id(&self, id: FilterId) -> Option { + self.stats.get(&id).and_then(|s| s.effectiveness()) + } + + /// Demote a filter to post-scan or drop it entirely if optional. + fn demote_or_drop( + &mut self, + id: FilterId, + expr: &Arc, + post_scan: &mut Vec<(FilterId, Arc)>, + ) { + if expr + .as_any() + .downcast_ref::() + .is_none() + { + self.filter_states.insert(id, FilterState::PostScan); + post_scan.push((id, Arc::clone(expr))); + // Reset stats for this filter so it can be re-evaluated as a post-scan filter. + self.stats.remove(&id); + } else { + self.filter_states.insert(id, FilterState::Dropped); + } + } + + /// Promote a filter to row-level. + fn promote( + &mut self, + id: FilterId, + expr: Arc, + row_filters: &mut Vec<(FilterId, Arc)>, + ) { + row_filters.push((id, expr)); + self.filter_states.insert(id, FilterState::RowFilter); + // Reset stats for this filter since it will be evaluated at row-level now. + self.stats.remove(&id); + } + + /// Update stats for a filter by ID after processing a batch. + fn update( + &mut self, + id: FilterId, + matched: u64, + total: u64, + eval_nanos: u64, + batch_bytes: u64, + ) { + self.stats + .entry(id) + .or_default() + .update(matched, total, eval_nanos, batch_bytes); + } + + /// Partition filters into collecting / promoted / post-scan buckets. + fn partition_filters( + &mut self, + filters: Vec<(FilterId, Arc)>, + projection_scan_size: usize, + projection_columns: &[usize], + metadata: &ParquetMetaData, + config: &TrackerConfig, + ) -> PartitionedFilters { + // If min_bytes_per_sec is INFINITY -> all filters are post-scan. + if config.min_bytes_per_sec.is_infinite() { + debug!( + "Filter promotion disabled via min_bytes_per_sec=INFINITY; all {} filters post-scan", + filters.len() + ); + return PartitionedFilters { + row_filters: Vec::new(), + post_scan: filters, + }; + } + // If min_bytes_per_sec is 0 -> all filters are promoted. + if config.min_bytes_per_sec == 0.0 { + debug!( + "All filters promoted via min_bytes_per_sec=0; all {} filters row-level", + filters.len() + ); + return PartitionedFilters { + row_filters: filters, + post_scan: Vec::new(), + }; + } + + // Note snapshot generations for dynamic filter detection. + // This clears stats for any filter whose generation has changed since the last scan. + // This must be done before any other logic since it can change filter states and stats. + for &(id, ref expr) in &filters { + let generation = snapshot_generation(expr); + self.note_generation(id, generation); + } + + // Separate into row filters and post-scan filters based on effectiveness and state. + let mut row_filters: Vec<(FilterId, Arc)> = Vec::new(); + let mut post_scan_filters: Vec<(FilterId, Arc)> = Vec::new(); + + let confidence_z = config.confidence_z; + for (id, expr) in filters { + let state = self.filter_states.get(&id).copied(); + + let Some(state) = state else { + // New filter: decide initial placement. + + // Optional/dynamic filters (e.g. hash join pushdown) always start + // PostScan because their selectivity is unknown and they can be + // dropped if ineffective. This is especially important for + // single-file tables where there's no second file to adapt. + let is_optional = expr + .as_any() + .downcast_ref::() + .is_some(); + if is_optional { + debug!( + "FilterId {id}: New optional filter → Post-scan (conservative) — {expr}" + ); + self.filter_states.insert(id, FilterState::PostScan); + post_scan_filters.push((id, expr)); + continue; + } + + // Static filters: compare I/O cost of row-filter vs post-scan. + // + // Post-scan I/O cost: 0 if filter columns are already in the + // projection (they're decoded anyway), otherwise the extra column bytes. + // + // Row-filter I/O cost: same column bytes, but enables late + // materialization (skipping other projected columns for pruned rows). + // However, late materialization has overhead for surviving rows. + // + // When extra_bytes == 0, post-scan has no I/O penalty, so it's the + // safe default — the adaptive system promotes if effective. + // When extra_bytes > 0 but small relative to projection, row-filter + // is worth trying since the extra I/O is cheap and pruning may help. + let filter_columns: Vec = collect_columns(&expr) + .iter() + .map(|col| col.index()) + .collect(); + let extra_columns: Vec = filter_columns + .iter() + .filter(|idx| !projection_columns.contains(idx)) + .copied() + .collect(); + let extra_bytes = + crate::row_filter::total_compressed_bytes(&extra_columns, metadata); + + if extra_bytes == 0 { + // Filter columns are entirely in the projection — no extra I/O + // for post-scan. Start PostScan; adaptive system promotes if + // row-level pruning proves effective. + debug!( + "FilterId {id}: New filter → Post-scan (filter columns in projection, zero extra I/O) — {expr}" + ); + self.filter_states.insert(id, FilterState::PostScan); + post_scan_filters.push((id, expr)); + } else { + let byte_ratio = extra_bytes as f64 / projection_scan_size as f64; + if byte_ratio <= config.byte_ratio_threshold { + debug!( + "FilterId {id}: New filter → Row filter via extra byte ratio {byte_ratio} <= threshold {} (extra_cols={}, filter_cols={}) — {expr}", + config.byte_ratio_threshold, + extra_columns.len(), + filter_columns.len() + ); + self.filter_states.insert(id, FilterState::RowFilter); + row_filters.push((id, expr)); + } else { + debug!( + "FilterId {id}: New filter → Post-scan via extra byte ratio {byte_ratio} > threshold {} (extra_cols={}, filter_cols={}) — {expr}", + config.byte_ratio_threshold, + extra_columns.len(), + filter_columns.len() + ); + self.filter_states.insert(id, FilterState::PostScan); + post_scan_filters.push((id, expr)); + } + } + continue; + }; + + match state { + FilterState::RowFilter => { + // Should we demote this filter based on CI upper bound? + if let Some(stats) = self.stats.get(&id) + && let Some(ub) = stats.confidence_upper_bound(confidence_z) + && ub < config.min_bytes_per_sec + { + debug!( + "FilterId {id}: Row filter → Post-scan via CI upper bound {ub} < {} bytes/sec — {expr}", + config.min_bytes_per_sec + ); + self.demote_or_drop(id, &expr, &mut post_scan_filters); + continue; + } + // If not demoted, keep as row filter. + row_filters.push((id, expr)); + } + FilterState::PostScan => { + // Should we promote this filter based on CI lower bound? + if let Some(stats) = self.stats.get(&id) + && let Some(lb) = stats.confidence_lower_bound(confidence_z) + && lb >= config.min_bytes_per_sec + { + debug!( + "FilterId {id}: Post-scan → Row filter via CI lower bound {lb} >= {} bytes/sec — {expr}", + config.min_bytes_per_sec + ); + self.promote(id, expr, &mut row_filters); + continue; + } + // Should we drop this filter if it's optional and ineffective? + // Non-optional filters must stay as post-scan regardless. + if let Some(stats) = self.stats.get(&id) + && let Some(ub) = stats.confidence_upper_bound(confidence_z) + && ub < config.min_bytes_per_sec + && expr + .as_any() + .downcast_ref::() + .is_some() + { + debug!( + "FilterId {id}: Post-scan → Dropped via CI upper bound {ub} < {} bytes/sec — {expr}", + config.min_bytes_per_sec + ); + self.filter_states.insert(id, FilterState::Dropped); + continue; + } + // Keep as post-scan filter (don't reset stats for mandatory filters). + post_scan_filters.push((id, expr)); + } + FilterState::Dropped => continue, + } + } + + // Sort row filters by: + // - Effectiveness (descending, higher = better) if available for both filters. + // - Scan size (ascending, cheapest first) as fallback — cheap filters prune + // rows before expensive ones, reducing downstream evaluation cost. + let cmp_row_filters = + |(id_a, expr_a): &(FilterId, Arc), + (id_b, expr_b): &(FilterId, Arc)| { + let eff_a = self.get_effectiveness_by_id(*id_a); + let eff_b = self.get_effectiveness_by_id(*id_b); + if let (Some(eff_a), Some(eff_b)) = (eff_a, eff_b) { + eff_b + .partial_cmp(&eff_a) + .unwrap_or(std::cmp::Ordering::Equal) + } else { + let size_a = filter_scan_size(expr_a, metadata); + let size_b = filter_scan_size(expr_b, metadata); + size_a.cmp(&size_b) + } + }; + row_filters.sort_by(cmp_row_filters); + // Post-scan filters: same logic (cheaper post-scan filters first to reduce + // the batch size for subsequent filters). + post_scan_filters.sort_by(cmp_row_filters); + + debug!( + "Partitioned filters: {} row-level, {} post-scan", + row_filters.len(), + post_scan_filters.len() + ); + PartitionedFilters { + row_filters, + post_scan: post_scan_filters, + } + } +} + +/// Calculate the estimated number of bytes needed to evaluate a filter based on the columns +/// it references as if it were applied to the entire file. +/// This is used for initial placement of new filters before any stats are available, and as a fallback for filters without stats. +fn filter_scan_size(expr: &Arc, metadata: &ParquetMetaData) -> usize { + let columns: Vec = collect_columns(expr) + .iter() + .map(|col| col.index()) + .collect(); + + crate::row_filter::total_compressed_bytes(&columns, metadata) +} + +#[cfg(test)] +mod tests { + use super::*; + use datafusion_physical_expr::expressions::Column; + use parquet::basic::Type as PhysicalType; + use parquet::file::metadata::{ColumnChunkMetaData, FileMetaData, RowGroupMetaData}; + use parquet::schema::types::SchemaDescPtr; + use parquet::schema::types::Type as SchemaType; + use std::sync::Arc; + + mod helper_functions { + use super::*; + + /// Creates test ParquetMetaData with specified row groups and column sizes. + /// + /// # Arguments + /// * `specs` - Vec of (num_rows, vec![compressed_size]) tuples for each row group + pub fn create_test_metadata(specs: Vec<(i64, Vec)>) -> ParquetMetaData { + // Get the maximum number of columns from all specs + let num_columns = specs + .iter() + .map(|(_, sizes)| sizes.len()) + .max() + .unwrap_or(1); + let schema_descr = get_test_schema_descr_with_columns(num_columns); + + let row_group_metadata: Vec<_> = specs + .into_iter() + .map(|(num_rows, column_sizes)| { + let columns = column_sizes + .into_iter() + .enumerate() + .map(|(col_idx, size)| { + ColumnChunkMetaData::builder(schema_descr.column(col_idx)) + .set_num_values(num_rows) + .set_total_compressed_size(size as i64) + .build() + .unwrap() + }) + .collect(); + + RowGroupMetaData::builder(schema_descr.clone()) + .set_num_rows(num_rows) + .set_column_metadata(columns) + .build() + .unwrap() + }) + .collect(); + + let total_rows: i64 = row_group_metadata.iter().map(|rg| rg.num_rows()).sum(); + let file_metadata = + FileMetaData::new(1, total_rows, None, None, schema_descr.clone(), None); + + ParquetMetaData::new(file_metadata, row_group_metadata) + } + + /// Creates a simple column expression with given name and index. + pub fn col_expr(name: &str, index: usize) -> Arc { + Arc::new(Column::new(name, index)) + } + + /// Create schema with specified number of columns, each named "a", "b", etc. + pub fn get_test_schema_descr_with_columns(num_columns: usize) -> SchemaDescPtr { + use parquet::basic::LogicalType; + + let fields: Vec<_> = (0..num_columns) + .map(|i| { + let col_name = format!("{}", (b'a' + i as u8) as char); + SchemaType::primitive_type_builder( + &col_name, + PhysicalType::BYTE_ARRAY, + ) + .with_logical_type(Some(LogicalType::String)) + .build() + .unwrap() + }) + .map(Arc::new) + .collect(); + + let schema = SchemaType::group_type_builder("schema") + .with_fields(fields) + .build() + .unwrap(); + Arc::new(parquet::schema::types::SchemaDescriptor::new(Arc::new( + schema, + ))) + } + } + + mod selectivity_stats_tests { + use super::*; + + #[test] + fn test_effectiveness_basic_calculation() { + let mut stats = SelectivityStats::default(); + + // 100 rows total, 50 rows pruned (matched 50), 1 sec eval time, 10000 bytes seen + // bytes_per_row = 10000 / 100 = 100 + // bytes_saved = 50 * 100 = 5000 + // effectiveness = 5000 * 1e9 / 1e9 = 5000 + stats.update(50, 100, 1_000_000_000, 10_000); + + let eff = stats.effectiveness().unwrap(); + assert!((eff - 5000.0).abs() < 0.1); + } + + #[test] + fn test_effectiveness_zero_rows_total() { + let mut stats = SelectivityStats::default(); + stats.update(0, 0, 1_000_000_000, 10_000); + + assert_eq!(stats.effectiveness(), None); + } + + #[test] + fn test_effectiveness_zero_eval_nanos() { + let mut stats = SelectivityStats::default(); + stats.update(50, 100, 0, 10_000); + + assert_eq!(stats.effectiveness(), None); + } + + #[test] + fn test_effectiveness_zero_bytes_seen() { + let mut stats = SelectivityStats::default(); + stats.update(50, 100, 1_000_000_000, 0); + + assert_eq!(stats.effectiveness(), None); + } + + #[test] + fn test_effectiveness_all_rows_matched() { + let mut stats = SelectivityStats::default(); + // All rows matched (no pruning) + stats.update(100, 100, 1_000_000_000, 10_000); + + let eff = stats.effectiveness().unwrap(); + assert_eq!(eff, 0.0); + } + + #[test] + fn test_confidence_bounds_single_sample() { + let mut stats = SelectivityStats::default(); + stats.update(50, 100, 1_000_000_000, 10_000); + + // Single sample returns None for confidence bounds + assert_eq!(stats.confidence_lower_bound(2.0), None); + assert_eq!(stats.confidence_upper_bound(2.0), None); + } + + #[test] + fn test_welford_identical_samples() { + let mut stats = SelectivityStats::default(); + + // Add two identical samples + stats.update(50, 100, 1_000_000_000, 10_000); + stats.update(50, 100, 1_000_000_000, 10_000); + + // Variance should be 0 + assert_eq!(stats.sample_count, 2); + let lb = stats.confidence_lower_bound(2.0).unwrap(); + let ub = stats.confidence_upper_bound(2.0).unwrap(); + + // Both should be equal to the mean since variance is 0 + assert!((lb - ub).abs() < 0.01); + } + + #[test] + fn test_welford_variance_calculation() { + let mut stats = SelectivityStats::default(); + + // Add samples that will produce effectiveness values of ~100, ~200, ~300 + // These are constructed to give those exact effectiveness values + stats.update(50, 100, 1_000_000_000, 10_000); // eff ≈ 5000 + stats.update(40, 100, 1_000_000_000, 10_000); // eff ≈ 6000 + stats.update(30, 100, 1_000_000_000, 10_000); // eff ≈ 7000 + + // We should have 3 samples + assert_eq!(stats.sample_count, 3); + + // Mean should be 6000 + assert!((stats.eff_mean - 6000.0).abs() < 1.0); + + // Both bounds should be defined + let lb = stats.confidence_lower_bound(1.0).unwrap(); + let ub = stats.confidence_upper_bound(1.0).unwrap(); + + assert!(lb < stats.eff_mean); + assert!(ub > stats.eff_mean); + } + + #[test] + fn test_confidence_bounds_asymmetry() { + let mut stats = SelectivityStats::default(); + + stats.update(50, 100, 1_000_000_000, 10_000); + stats.update(40, 100, 1_000_000_000, 10_000); + + let lb = stats.confidence_lower_bound(2.0).unwrap(); + let ub = stats.confidence_upper_bound(2.0).unwrap(); + + // Bounds should be symmetric around the mean + let lower_dist = stats.eff_mean - lb; + let upper_dist = ub - stats.eff_mean; + + assert!((lower_dist - upper_dist).abs() < 0.01); + } + + #[test] + fn test_welford_incremental_vs_batch() { + // Create two identical stats objects + let mut stats_incremental = SelectivityStats::default(); + let mut stats_batch = SelectivityStats::default(); + + // Incremental: add one at a time + stats_incremental.update(50, 100, 1_000_000_000, 10_000); + stats_incremental.update(40, 100, 1_000_000_000, 10_000); + stats_incremental.update(30, 100, 1_000_000_000, 10_000); + + // Batch: simulate batch update (all at once) + stats_batch.update(120, 300, 3_000_000_000, 30_000); + + // Both should produce the same overall statistics + assert_eq!(stats_incremental.rows_total, stats_batch.rows_total); + assert_eq!(stats_incremental.rows_matched, stats_batch.rows_matched); + + // Means should be close + assert!((stats_incremental.eff_mean - stats_batch.eff_mean).abs() < 100.0); + } + + #[test] + fn test_effectiveness_numerical_stability() { + let mut stats = SelectivityStats::default(); + + // Test with large values to ensure numerical stability + stats.update( + 500_000_000, + 1_000_000_000, + 10_000_000_000_000, + 1_000_000_000_000, + ); + + let eff = stats.effectiveness(); + assert!(eff.is_some()); + assert!(eff.unwrap() > 0.0); + assert!(!eff.unwrap().is_nan()); + assert!(!eff.unwrap().is_infinite()); + } + } + + mod tracker_config_tests { + use super::*; + + #[test] + fn test_default_config() { + let config = TrackerConfig::default(); + + assert!(config.min_bytes_per_sec.is_infinite()); + assert_eq!(config.byte_ratio_threshold, 0.05); + assert_eq!(config.confidence_z, 2.0); + } + + #[test] + fn test_with_min_bytes_per_sec() { + let config = TrackerConfig::new().with_min_bytes_per_sec(1000.0); + + assert_eq!(config.min_bytes_per_sec, 1000.0); + } + + #[test] + fn test_with_byte_ratio_threshold() { + let config = TrackerConfig::new().with_byte_ratio_threshold(0.5); + + assert_eq!(config.byte_ratio_threshold, 0.5); + } + + #[test] + fn test_with_confidence_z() { + let config = TrackerConfig::new().with_confidence_z(3.0); + + assert_eq!(config.confidence_z, 3.0); + } + + #[test] + fn test_builder_chain() { + let config = TrackerConfig::new() + .with_min_bytes_per_sec(500.0) + .with_byte_ratio_threshold(0.3) + .with_confidence_z(1.5); + + assert_eq!(config.min_bytes_per_sec, 500.0); + assert_eq!(config.byte_ratio_threshold, 0.3); + assert_eq!(config.confidence_z, 1.5); + } + + #[test] + fn test_build_creates_tracker() { + let tracker = TrackerConfig::new().with_min_bytes_per_sec(1000.0).build(); + + // Tracker should be created and functional + assert_eq!(tracker.config.min_bytes_per_sec, 1000.0); + } + } + + mod state_machine_tests { + use super::helper_functions::*; + use super::*; + + #[test] + fn test_initial_placement_low_byte_ratio() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.2) + .build(); + + // Create metadata: 1 row group, 100 rows, 1000 bytes for column + let metadata = create_test_metadata(vec![(100, vec![1000])]); + + // Filter using column 0 (1000 bytes out of 1000 projection = 100% ratio > 0.2) + // So this should be placed in post-scan initially + let expr = col_expr("a", 0); + let filters = vec![(1, expr)]; + + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + + // With 100% byte ratio, should go to post-scan + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 1); + } + + #[test] + fn test_initial_placement_filter_in_projection_starts_postscan() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.5) + .build(); + + // Create metadata: 1 row group, 100 rows, 100 bytes for column + let metadata = create_test_metadata(vec![(100, vec![100])]); + + // Filter using column 0 which IS in the projection + let expr = col_expr("a", 0); + let filters = vec![(1, expr)]; + + // projection_columns includes col 0 → extra_bytes = 0 → PostScan + let result = tracker.partition_filters(filters, 1000, &[0], &metadata); + + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 1); + } + + #[test] + fn test_initial_placement_high_byte_ratio() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.5) + .build(); + + // Create metadata: 1 row group, 100 rows, 100 bytes for column + let metadata = create_test_metadata(vec![(100, vec![100])]); + + // Filter using column 0 (100 bytes / 1000 projection = 10% ratio <= 0.5) + // So this should be placed in row-filter immediately + let expr = col_expr("a", 0); + let filters = vec![(1, expr)]; + + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + + // With 10% byte ratio, should go to row-filter + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 0); + } + + #[test] + fn test_min_bytes_per_sec_infinity_disables_promotion() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(f64::INFINITY) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![100])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr)]; + + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + + // All filters should go to post_scan when min_bytes_per_sec is INFINITY + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 1); + } + + #[test] + fn test_min_bytes_per_sec_zero_promotes_all() { + let tracker = TrackerConfig::new().with_min_bytes_per_sec(0.0).build(); + + let metadata = create_test_metadata(vec![(100, vec![1000])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr)]; + + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + + // All filters should be promoted to row_filters when min_bytes_per_sec is 0 + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 0); + } + + #[test] + fn test_promotion_via_confidence_lower_bound() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.5) // Force to PostScan initially + .with_confidence_z(0.5) // Lower z for easier promotion + .build(); + + let metadata = create_test_metadata(vec![(100, vec![1000])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // First partition: goes to PostScan (high byte ratio) + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + assert_eq!(result.post_scan.len(), 1); + assert_eq!(result.row_filters.len(), 0); + + // Feed high effectiveness stats + for _ in 0..5 { + tracker.update(1, 10, 100, 100_000, 1000); // high effectiveness + } + + // Second partition: should be promoted to RowFilter + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 0); + } + + #[test] + fn test_demotion_via_confidence_upper_bound() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(10000.0) + .with_byte_ratio_threshold(0.1) // Force to RowFilter initially + .with_confidence_z(0.5) // Lower z for easier demotion + .build(); + + let metadata = create_test_metadata(vec![(100, vec![100])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // First partition: goes to RowFilter (low byte ratio) + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 0); + + // Feed low effectiveness stats + for _ in 0..5 { + tracker.update(1, 100, 100, 100_000, 1000); // all rows matched, no pruning + } + + // Second partition: should be demoted to PostScan + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 1); + } + + #[test] + fn test_demotion_resets_stats() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(10000.0) + .with_byte_ratio_threshold(0.1) + .with_confidence_z(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![100])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // Start as RowFilter + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + // Add stats + tracker.update(1, 100, 100, 100_000, 1000); + tracker.update(1, 100, 100, 100_000, 1000); + + // Demote + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + // Stats should be cleared, so on next update it starts fresh + assert_eq!(tracker.inner.read().stats.len(), 0); + } + + #[test] + fn test_promotion_resets_stats() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(100.0) + .with_byte_ratio_threshold(0.5) + .with_confidence_z(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![1000])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // Start as PostScan + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + // Add stats + for _ in 0..3 { + tracker.update(1, 50, 100, 100_000, 1000); + } + + // Promote + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + // Stats should be cleared after promotion + assert_eq!(tracker.inner.read().stats.len(), 0); + } + + #[test] + fn test_optional_filter_dropping() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(10000.0) + .with_byte_ratio_threshold(0.5) + .with_confidence_z(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![1000])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // Start as PostScan + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + // Feed poor effectiveness stats + for _ in 0..5 { + tracker.update(1, 100, 100, 100_000, 1000); // no pruning + } + + // Next partition: should stay as PostScan (not dropped because not optional) + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!(result.post_scan.len(), 1); + assert_eq!(result.row_filters.len(), 0); + } + + #[test] + fn test_persistent_dropped_state() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(10000.0) + .with_byte_ratio_threshold(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![1000])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // Mark filter as dropped by manually setting state + tracker + .inner + .write() + .filter_states + .insert(1, FilterState::Dropped); + + // On next partition, dropped filters should not reappear + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 0); + } + } + + mod filter_ordering_tests { + use super::helper_functions::*; + use super::*; + + #[test] + fn test_filters_get_partitioned() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1.0) // Very low threshold + .build(); + + let metadata = create_test_metadata(vec![(100, vec![100, 100, 100])]); + let filters = vec![ + (1, col_expr("a", 0)), + (2, col_expr("a", 1)), + (3, col_expr("a", 2)), + ]; + + // Partition should process all filters + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + // With min_bytes_per_sec=1.0, filters should be partitioned + assert!(result.row_filters.len() + result.post_scan.len() > 0); + + // Add stats and partition again + tracker.update(1, 60, 100, 1_000_000, 100); + tracker.update(2, 10, 100, 1_000_000, 100); + tracker.update(3, 40, 100, 1_000_000, 100); + + let result2 = tracker.partition_filters(filters, 1000, &[], &metadata); + + // Filters should still be partitioned + assert!(result2.row_filters.len() + result2.post_scan.len() > 0); + } + + #[test] + fn test_filters_processed_without_stats() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1.0) // Very low threshold + .build(); + + // Different column sizes: 300, 200, 100 bytes + let metadata = create_test_metadata(vec![(100, vec![300, 200, 100])]); + let filters = vec![ + (1, col_expr("a", 0)), + (2, col_expr("a", 1)), + (3, col_expr("a", 2)), + ]; + + // First partition - no stats yet + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + // All filters should be processed (partitioned into row/post-scan) + assert!(result.row_filters.len() + result.post_scan.len() > 0); + + // Filters should be consistent on repeated calls + let result2 = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!( + result.row_filters.len() + result.post_scan.len(), + result2.row_filters.len() + result2.post_scan.len() + ); + } + + #[test] + fn test_filters_with_partial_stats() { + let tracker = TrackerConfig::new().with_min_bytes_per_sec(1.0).build(); + + // Give filter 2 larger bytes so it's prioritized when falling back to byte ratio + let metadata = create_test_metadata(vec![(100, vec![100, 300, 100])]); + let filters = vec![ + (1, col_expr("a", 0)), + (2, col_expr("a", 1)), + (3, col_expr("a", 2)), + ]; + + // First partition + let result1 = + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + assert!(result1.row_filters.len() + result1.post_scan.len() > 0); + + // Only add stats for filters 1 and 3, not 2 + tracker.update(1, 60, 100, 1_000_000, 100); + tracker.update(3, 60, 100, 1_000_000, 100); + + // Second partition with partial stats + let result2 = tracker.partition_filters(filters, 1000, &[], &metadata); + assert!(result2.row_filters.len() + result2.post_scan.len() > 0); + } + + #[test] + fn test_ordering_stability_with_identical_values() { + let tracker = TrackerConfig::new().with_min_bytes_per_sec(0.0).build(); + + let metadata = create_test_metadata(vec![(100, vec![100, 100, 100])]); + let filters = vec![ + (1, col_expr("a", 0)), + (2, col_expr("a", 1)), + (3, col_expr("a", 2)), + ]; + + let result1 = + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + let result2 = tracker.partition_filters(filters, 1000, &[], &metadata); + + // Without stats and with identical byte sizes, order should be stable + assert_eq!(result1.row_filters[0].0, result2.row_filters[0].0); + assert_eq!(result1.row_filters[1].0, result2.row_filters[1].0); + assert_eq!(result1.row_filters[2].0, result2.row_filters[2].0); + } + } + + mod dynamic_filter_tests { + use super::helper_functions::*; + use super::*; + + #[test] + fn test_generation_zero_ignored() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![1000])]); + + // Create two filters with same ID but generation 0 and 1 + // Generation 0 should be ignored + let expr1 = col_expr("a", 0); + let filters1 = vec![(1, expr1)]; + + tracker.partition_filters(filters1, 1000, &[], &metadata); + tracker.update(1, 50, 100, 100_000, 1000); + + // Generation 0 doesn't trigger state reset + let snapshot_gen = tracker.inner.read().snapshot_generations.get(&1).copied(); + assert_eq!(snapshot_gen, None); + } + + #[test] + fn test_generation_change_clears_stats() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.5) + .build(); + + // Initialize generation to 100 + tracker.inner.write().note_generation(1, 100); + + // Add stats + tracker.update(1, 50, 100, 100_000, 1000); + tracker.update(1, 50, 100, 100_000, 1000); + + let stats_before = tracker.inner.read().stats.contains_key(&1); + assert!(stats_before); + + // Simulate generation change to a different value + tracker.inner.write().note_generation(1, 101); + + // Stats should be cleared on generation change + let stats_after = tracker.inner.read().stats.contains_key(&1); + assert!(!stats_after); + } + + #[test] + fn test_generation_unchanged_preserves_stats() { + let tracker = TrackerConfig::new().with_min_bytes_per_sec(1000.0).build(); + + // Manually set generation + tracker.inner.write().note_generation(1, 100); + + // Add stats + tracker.update(1, 50, 100, 100_000, 1000); + tracker.update(1, 50, 100, 100_000, 1000); + + let sample_count_before = + tracker.inner.read().stats.get(&1).map(|s| s.sample_count); + assert_eq!(sample_count_before, Some(2)); + + // Call note_generation with same generation + tracker.inner.write().note_generation(1, 100); + + // Stats should be preserved + let sample_count_after = + tracker.inner.read().stats.get(&1).map(|s| s.sample_count); + assert_eq!(sample_count_after, Some(2)); + } + + #[test] + fn test_generation_change_preserves_state() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.1) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![100])]); + + // First partition: goes to RowFilter + let expr = col_expr("a", 0); + let filters = vec![(1, expr)]; + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + let state_before = tracker.inner.read().filter_states.get(&1).copied(); + assert_eq!(state_before, Some(FilterState::RowFilter)); + + // Simulate generation change + tracker.inner.write().note_generation(1, 100); + + // State should be preserved despite stats being cleared + let state_after = tracker.inner.read().filter_states.get(&1).copied(); + assert_eq!(state_after, Some(FilterState::RowFilter)); + } + + #[test] + fn test_generation_change_undrops_dropped_filter() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.1) + .build(); + + // Manually set filter state to Dropped + tracker + .inner + .write() + .filter_states + .insert(1, FilterState::Dropped); + tracker.inner.write().note_generation(1, 100); + + // Simulate generation change + tracker.inner.write().note_generation(1, 101); + + // Dropped filter should be un-dropped to PostScan + let state_after = tracker.inner.read().filter_states.get(&1).copied(); + assert_eq!(state_after, Some(FilterState::PostScan)); + } + + #[test] + fn test_multiple_filters_independent_generation_tracking() { + let tracker = TrackerConfig::new().with_min_bytes_per_sec(1000.0).build(); + + // Set generations for multiple filters + tracker.inner.write().note_generation(1, 100); + tracker.inner.write().note_generation(2, 200); + + // Add stats to both + tracker.update(1, 50, 100, 100_000, 1000); + tracker.update(2, 50, 100, 100_000, 1000); + + // Change generation of filter 1 only + tracker.inner.write().note_generation(1, 101); + + // Filter 1 stats should be cleared, filter 2 preserved + assert!(!tracker.inner.read().stats.contains_key(&1)); + assert!(tracker.inner.read().stats.contains_key(&2)); + } + } + + mod integration_tests { + use super::helper_functions::*; + use super::*; + + #[test] + fn test_full_promotion_lifecycle() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(500.0) + .with_byte_ratio_threshold(0.5) // Force initial PostScan + .with_confidence_z(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![1000])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // Step 1: Initial placement (PostScan) + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + assert_eq!(result.post_scan.len(), 1); + assert_eq!(result.row_filters.len(), 0); + + // Step 2: Accumulate high effectiveness stats + for _ in 0..5 { + tracker.update(1, 10, 100, 100_000, 1000); // high effectiveness + } + + // Step 3: Promotion should occur + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 0); + + // Step 4: Continue to partition without additional updates + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 0); + } + + #[test] + fn test_full_demotion_lifecycle() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(10000.0) + .with_byte_ratio_threshold(0.1) // Force initial RowFilter + .with_confidence_z(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![100])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // Step 1: Initial placement (RowFilter) + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 0); + + // Step 2: Accumulate low effectiveness stats + for _ in 0..5 { + tracker.update(1, 100, 100, 100_000, 1000); // no pruning + } + + // Step 3: Demotion should occur + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 1); + + // Step 4: Continue to partition without additional updates + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 1); + } + + #[test] + fn test_multiple_filters_mixed_states() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.4) // Force PostScan initially (500/1000=0.5 > 0.4) + .with_confidence_z(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![500, 500])]); + let filters = vec![(1, col_expr("a", 0)), (2, col_expr("a", 1))]; + + // Initial partition: both go to PostScan (500/1000 = 0.5 > 0.4) + let result = tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + assert_eq!(result.post_scan.len(), 2); + + // Filter 1: high effectiveness (promote) + for _ in 0..3 { + tracker.update(1, 10, 100, 100_000, 500); + } + + // Filter 2: low effectiveness (stay PostScan) + for _ in 0..3 { + tracker.update(2, 100, 100, 100_000, 500); + } + + // Next partition: Filter 1 promoted, Filter 2 stays PostScan + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 1); + assert_eq!(result.row_filters[0].0, 1); + assert_eq!(result.post_scan[0].0, 2); + } + + #[test] + fn test_empty_filter_list() { + let tracker = TrackerConfig::new().build(); + let metadata = create_test_metadata(vec![(100, vec![1000])]); + let filters = vec![]; + + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 0); + } + + #[test] + fn test_single_filter() { + let tracker = TrackerConfig::new().with_min_bytes_per_sec(0.0).build(); + + let metadata = create_test_metadata(vec![(100, vec![100])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr)]; + + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + + assert_eq!(result.row_filters.len(), 1); + assert_eq!(result.post_scan.len(), 0); + } + + #[test] + fn test_zero_effectiveness_stays_at_boundary() { + let tracker = TrackerConfig::new() + .with_min_bytes_per_sec(100.0) + .with_byte_ratio_threshold(0.1) + .with_confidence_z(0.5) + .build(); + + let metadata = create_test_metadata(vec![(100, vec![100])]); + let expr = col_expr("a", 0); + let filters = vec![(1, expr.clone())]; + + // Start as RowFilter + tracker.partition_filters(filters.clone(), 1000, &[], &metadata); + + // All rows match (zero effectiveness) + for _ in 0..5 { + tracker.update(1, 100, 100, 100_000, 100); + } + + // Should demote due to CI upper bound being 0 + let result = tracker.partition_filters(filters, 1000, &[], &metadata); + assert_eq!(result.row_filters.len(), 0); + assert_eq!(result.post_scan.len(), 1); + } + + #[test] + fn test_confidence_z_parameter_stored() { + // Test that different confidence_z values are properly stored in config + let tracker_conservative = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.5) + .with_confidence_z(3.0) // Harder to promote + .build(); + + let tracker_aggressive = TrackerConfig::new() + .with_min_bytes_per_sec(1000.0) + .with_byte_ratio_threshold(0.5) + .with_confidence_z(0.5) // Easier to promote + .build(); + + // Verify configs are stored correctly + assert_eq!(tracker_conservative.config.confidence_z, 3.0); + assert_eq!(tracker_aggressive.config.confidence_z, 0.5); + + // The z-score affects confidence intervals during promotion/demotion decisions. + // With identical stats, higher z requires narrower confidence intervals, + // making promotion harder. With lower z, confidence intervals are wider, + // making promotion easier. This is tested in other integration tests + // that verify actual promotion/demotion behavior. + } + } +} diff --git a/datafusion/datasource-parquet/src/source.rs b/datafusion/datasource-parquet/src/source.rs index 75d87a4cd16fc..bb2c46aa61abd 100644 --- a/datafusion/datasource-parquet/src/source.rs +++ b/datafusion/datasource-parquet/src/source.rs @@ -38,8 +38,9 @@ use datafusion_common::config::TableParquetOptions; use datafusion_datasource::TableSchema; use datafusion_datasource::file::FileSource; use datafusion_datasource::file_scan_config::FileScanConfig; +use datafusion_physical_expr::EquivalenceProperties; +use datafusion_physical_expr::conjunction; use datafusion_physical_expr::projection::ProjectionExprs; -use datafusion_physical_expr::{EquivalenceProperties, conjunction}; use datafusion_physical_expr_adapter::DefaultPhysicalExprAdapterFactory; use datafusion_physical_expr_common::physical_expr::PhysicalExpr; use datafusion_physical_expr_common::physical_expr::fmt_sql; @@ -276,8 +277,10 @@ pub struct ParquetSource { /// In particular, this is the schema of the table without partition columns, /// *not* the physical schema of the file. pub(crate) table_schema: TableSchema, - /// Optional predicate for row filtering during parquet scan - pub(crate) predicate: Option>, + /// Optional predicate conjuncts for row filtering during parquet scan. + /// Each conjunct is tagged with a stable FilterId for selectivity tracking. + pub(crate) predicate_conjuncts: + Option)>>, /// Optional user defined parquet file reader factory pub(crate) parquet_file_reader_factory: Option>, /// Batch size configuration @@ -293,6 +296,10 @@ pub struct ParquetSource { /// so we still need to sort them after reading, so the reverse scan is inexact. /// Used to optimize ORDER BY ... DESC on sorted data. reverse_row_groups: bool, + /// Tracks filter selectivity across files for adaptive filter reordering. + /// Shared across all openers - each opener reads stats and makes its own + /// decision about which filters to push down vs. apply post-scan. + pub(crate) selectivity_tracker: Arc, } impl ParquetSource { @@ -311,13 +318,16 @@ impl ParquetSource { table_schema, table_parquet_options: TableParquetOptions::default(), metrics: ExecutionPlanMetricsSet::new(), - predicate: None, + predicate_conjuncts: None, parquet_file_reader_factory: None, batch_size: None, metadata_size_hint: None, #[cfg(feature = "parquet_encryption")] encryption_factory: None, reverse_row_groups: false, + selectivity_tracker: Arc::new( + crate::selectivity::SelectivityTracker::default(), + ), } } @@ -326,6 +336,15 @@ impl ParquetSource { mut self, table_parquet_options: TableParquetOptions, ) -> Self { + // Update the selectivity tracker from the config + let opts = &table_parquet_options.global; + self.selectivity_tracker = Arc::new( + crate::selectivity::TrackerConfig::new() + .with_min_bytes_per_sec(opts.filter_pushdown_min_bytes_per_sec) + .with_byte_ratio_threshold(opts.filter_collecting_byte_ratio_threshold) + .with_confidence_z(opts.filter_confidence_z) + .build(), + ); self.table_parquet_options = table_parquet_options; self } @@ -341,11 +360,23 @@ impl ParquetSource { self } - /// Set predicate information + /// Set predicate information. + /// + /// The predicate is split into conjuncts and each is assigned a stable + /// `FilterId` (its index in the conjunct list). These IDs are used for + /// selectivity tracking across files, avoiding ExprKey mismatch issues + /// when expressions are rebased or simplified per-file. #[expect(clippy::needless_pass_by_value)] pub fn with_predicate(&self, predicate: Arc) -> Self { + use datafusion_physical_expr::split_conjunction; let mut conf = self.clone(); - conf.predicate = Some(Arc::clone(&predicate)); + let conjuncts: Vec<(crate::selectivity::FilterId, Arc)> = + split_conjunction(&predicate) + .into_iter() + .enumerate() + .map(|(id, expr)| (id, Arc::clone(expr))) + .collect(); + conf.predicate_conjuncts = Some(conjuncts); conf } @@ -366,8 +397,15 @@ impl ParquetSource { /// Optional predicate. #[deprecated(since = "50.2.0", note = "use `filter` instead")] - pub fn predicate(&self) -> Option<&Arc> { - self.predicate.as_ref() + pub fn predicate(&self) -> Option> { + self.combined_predicate() + } + + /// Build a combined predicate from the conjuncts, if any. + fn combined_predicate(&self) -> Option> { + self.predicate_conjuncts + .as_ref() + .map(|conjuncts| conjunction(conjuncts.iter().map(|(_, e)| Arc::clone(e)))) } /// return the optional file reader factory @@ -398,22 +436,6 @@ impl ParquetSource { self.table_parquet_options.global.pushdown_filters } - /// If true, the `RowFilter` made by `pushdown_filters` may try to - /// minimize the cost of filter evaluation by reordering the - /// predicate [`Expr`]s. If false, the predicates are applied in - /// the same order as specified in the query. Defaults to false. - /// - /// [`Expr`]: datafusion_expr::Expr - pub fn with_reorder_filters(mut self, reorder_filters: bool) -> Self { - self.table_parquet_options.global.reorder_filters = reorder_filters; - self - } - - /// Return the value described in [`Self::with_reorder_filters`] - fn reorder_filters(&self) -> bool { - self.table_parquet_options.global.reorder_filters - } - /// Return the value of [`datafusion_common::config::ParquetOptions::force_filter_selections`] fn force_filter_selections(&self) -> bool { self.table_parquet_options.global.force_filter_selections @@ -549,13 +571,12 @@ impl FileSource for ParquetSource { .expect("Batch size must set before creating ParquetOpener"), limit: base_config.limit, preserve_order: base_config.preserve_order, - predicate: self.predicate.clone(), + predicate_conjuncts: self.predicate_conjuncts.clone(), table_schema: self.table_schema.clone(), metadata_size_hint: self.metadata_size_hint, metrics: self.metrics().clone(), parquet_file_reader_factory, pushdown_filters: self.pushdown_filters(), - reorder_filters: self.reorder_filters(), force_filter_selections: self.force_filter_selections(), enable_page_index: self.enable_page_index(), enable_bloom_filter: self.bloom_filter_on_read(), @@ -568,7 +589,9 @@ impl FileSource for ParquetSource { encryption_factory: self.get_encryption_factory_with_config(), max_predicate_cache_size: self.max_predicate_cache_size(), reverse_row_groups: self.reverse_row_groups, + selectivity_tracker: Arc::clone(&self.selectivity_tracker), }); + Ok(opener) } @@ -581,7 +604,7 @@ impl FileSource for ParquetSource { } fn filter(&self) -> Option> { - self.predicate.clone() + self.combined_predicate() } fn with_batch_size(&self, batch_size: usize) -> Arc { @@ -634,7 +657,7 @@ impl FileSource for ParquetSource { // the actual predicates are built in reference to the physical schema of // each file, which we do not have at this point and hence cannot use. // Instead we use the logical schema of the file (the table schema without partition columns). - if let Some(predicate) = &self.predicate { + if let Some(predicate) = &self.combined_predicate() { let predicate_creation_errors = Count::new(); if let (Some(pruning_predicate), _) = build_pruning_predicates( Some(predicate), @@ -711,13 +734,16 @@ impl FileSource for ParquetSource { PushedDown::No => None, }) .collect_vec(); - let predicate = match source.predicate { - Some(predicate) => { - conjunction(std::iter::once(predicate).chain(allowed_filters)) - } - None => conjunction(allowed_filters), - }; - source.predicate = Some(predicate); + // Merge existing conjuncts with new allowed filters + let mut all_conjuncts: Vec> = source + .predicate_conjuncts + .as_ref() + .map(|c| c.iter().map(|(_, e)| Arc::clone(e)).collect()) + .unwrap_or_default(); + all_conjuncts.extend(allowed_filters); + // Re-assign FilterIds by index + source.predicate_conjuncts = + Some(all_conjuncts.into_iter().enumerate().collect()); source = source.with_pushdown_filters(pushdown_filters); let source = Arc::new(source); // If pushdown_filters is false we tell our parents that they still have to handle the filters, @@ -831,8 +857,9 @@ mod tests { let parquet_source = ParquetSource::new(Arc::new(Schema::empty())).with_predicate(predicate); - // same value. but filter() call Arc::clone internally - assert_eq!(parquet_source.predicate(), parquet_source.filter().as_ref()); + // Both should return equivalent predicates + assert!(parquet_source.predicate().is_some()); + assert!(parquet_source.filter().is_some()); } #[test] diff --git a/datafusion/datasource/src/file_scan_config.rs b/datafusion/datasource/src/file_scan_config.rs index c3e5cabce7bc2..92e61aa16cf4b 100644 --- a/datafusion/datasource/src/file_scan_config.rs +++ b/datafusion/datasource/src/file_scan_config.rs @@ -20,9 +20,13 @@ use crate::file_groups::FileGroup; use crate::{ - PartitionedFile, display::FileGroupsDisplay, file::FileSource, - file_compression_type::FileCompressionType, file_stream::FileStream, - source::DataSource, statistics::MinMaxStatistics, + PartitionedFile, + display::FileGroupsDisplay, + file::FileSource, + file_compression_type::FileCompressionType, + file_stream::{FileStream, WorkQueue}, + source::DataSource, + statistics::MinMaxStatistics, }; use arrow::datatypes::FieldRef; use arrow::datatypes::{DataType, Schema, SchemaRef}; @@ -204,6 +208,9 @@ pub struct FileScanConfig { /// If the number of file partitions > target_partitions, the file partitions will be grouped /// in a round-robin fashion such that number of file partitions = target_partitions. pub partitioned_by_file_group: bool, + /// When true, use morsel-driven execution to avoid data skew. + /// This means all partitions share a single pool of work. + pub morsel_driven: bool, } /// A builder for [`FileScanConfig`]'s. @@ -274,6 +281,7 @@ pub struct FileScanConfigBuilder { batch_size: Option, expr_adapter_factory: Option>, partitioned_by_file_group: bool, + morsel_driven: bool, } impl FileScanConfigBuilder { @@ -300,6 +308,7 @@ impl FileScanConfigBuilder { batch_size: None, expr_adapter_factory: None, partitioned_by_file_group: false, + morsel_driven: false, } } @@ -500,6 +509,12 @@ impl FileScanConfigBuilder { self } + /// Set whether to use morsel-driven execution. + pub fn with_morsel_driven(mut self, morsel_driven: bool) -> Self { + self.morsel_driven = morsel_driven; + self + } + /// Build the final [`FileScanConfig`] with all the configured settings. /// /// This method takes ownership of the builder and returns the constructed `FileScanConfig`. @@ -521,6 +536,7 @@ impl FileScanConfigBuilder { batch_size, expr_adapter_factory: expr_adapter, partitioned_by_file_group, + morsel_driven, } = self; let constraints = constraints.unwrap_or_default(); @@ -533,6 +549,24 @@ impl FileScanConfigBuilder { // If there is an output ordering, we should preserve it. let preserve_order = preserve_order || !output_ordering.is_empty(); + // Morsel-driven execution pools all files from all file groups into a shared + // work queue that any partition may consume, allowing partitions to steal work + // from each other's file groups. This breaks two guarantees that downstream + // operators may rely on: + // + // 1. `partitioned_by_file_group`: the optimizer has declared Hash partitioning + // assuming partition N reads only from file_group[N] (e.g. Hive-style + // partitioning with `preserve_file_partitions`). Morsel-driven stealing + // would violate this, breaking `HashJoinExec: mode=Partitioned` correctness. + // + // 2. `preserve_order`: the scan declares a sort order on its output. When a + // partition interleaves morsels from multiple files (from different groups), + // the per-partition output is no longer globally sorted. Downstream operators + // such as `SortPreservingMergeExec` rely on each partition's stream being + // pre-sorted. + let morsel_driven = + morsel_driven && !partitioned_by_file_group && !preserve_order; + FileScanConfig { object_store_url, file_source, @@ -546,6 +580,7 @@ impl FileScanConfigBuilder { expr_adapter_factory: expr_adapter, statistics, partitioned_by_file_group, + morsel_driven, } } } @@ -565,15 +600,18 @@ impl From for FileScanConfigBuilder { batch_size: config.batch_size, expr_adapter_factory: config.expr_adapter_factory, partitioned_by_file_group: config.partitioned_by_file_group, + morsel_driven: config.morsel_driven, } } } -impl DataSource for FileScanConfig { - fn open( +impl FileScanConfig { + /// Open a partition stream with an optional shared morsel queue. + pub(crate) fn open_with_queue( &self, partition: usize, - context: Arc, + context: &Arc, + queue: Option>, ) -> Result { let object_store = context.runtime_env().object_store(&self.object_store_url)?; let batch_size = self @@ -581,12 +619,25 @@ impl DataSource for FileScanConfig { .unwrap_or_else(|| context.session_config().batch_size()); let source = self.file_source.with_batch_size(batch_size); - let opener = source.create_file_opener(object_store, self, partition)?; let stream = FileStream::new(self, partition, opener, source.metrics())?; + let stream = match queue { + Some(q) => stream.with_shared_queue(q), + None => stream, + }; Ok(Box::pin(cooperative(stream))) } +} + +impl DataSource for FileScanConfig { + fn open( + &self, + partition: usize, + context: Arc, + ) -> Result { + self.open_with_queue(partition, &context, None) + } fn as_any(&self) -> &dyn Any { self @@ -667,6 +718,29 @@ impl DataSource for FileScanConfig { return Ok(None); } + // With morsel-driven execution, the shared WorkQueue handles load + // balancing at runtime so byte-range splitting is unnecessary. + // Just distribute whole files round-robin across target partitions. + if self.morsel_driven { + let all_files: Vec<_> = self + .file_groups + .iter() + .flat_map(|g| g.files().iter().cloned()) + .collect(); + if all_files.is_empty() { + return Ok(None); + } + let mut groups: Vec> = + (0..target_partitions).map(|_| vec![]).collect(); + for (i, file) in all_files.into_iter().enumerate() { + groups[i % target_partitions].push(file); + } + let file_groups = groups.into_iter().map(FileGroup::new).collect(); + let mut source = self.clone(); + source.file_groups = file_groups; + return Ok(Some(Arc::new(source))); + } + let source = self.file_source.repartitioned( target_partitions, repartition_file_min_size, diff --git a/datafusion/datasource/src/file_stream.rs b/datafusion/datasource/src/file_stream.rs index c8090382094ef..57c126a2663ec 100644 --- a/datafusion/datasource/src/file_stream.rs +++ b/datafusion/datasource/src/file_stream.rs @@ -24,8 +24,10 @@ use std::collections::VecDeque; use std::mem; use std::pin::Pin; -use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex}; use std::task::{Context, Poll}; +use tokio::sync::Notify; use crate::PartitionedFile; use crate::file_scan_config::FileScanConfig; @@ -43,10 +45,23 @@ use futures::future::BoxFuture; use futures::stream::BoxStream; use futures::{FutureExt as _, Stream, StreamExt as _, ready}; +/// A guard that decrements the morselizing count when dropped. +struct MorselizingGuard { + queue: Arc, +} + +impl Drop for MorselizingGuard { + fn drop(&mut self) { + self.queue.stop_morselizing(); + } +} + /// A stream that iterates record batch by record batch, file over file. pub struct FileStream { /// An iterator over input files. file_iter: VecDeque, + /// Shared work queue for morsel-driven execution. + shared_queue: Option>, /// The stream schema (file schema including partition columns and after /// projection). projected_schema: SchemaRef, @@ -63,6 +78,8 @@ pub struct FileStream { baseline_metrics: BaselineMetrics, /// Describes the behavior of the `FileStream` if file opening or scanning fails on_error: OnError, + /// Guard for morselizing state to ensure counter is decremented on drop + morsel_guard: Option, } impl FileStream { @@ -75,10 +92,16 @@ impl FileStream { ) -> Result { let projected_schema = config.projected_schema()?; - let file_group = config.file_groups[partition].clone(); + let file_iter = if config.morsel_driven { + VecDeque::new() + } else { + let file_group = config.file_groups[partition].clone(); + file_group.into_inner().into_iter().collect() + }; Ok(Self { - file_iter: file_group.into_inner().into_iter().collect(), + file_iter, + shared_queue: None, projected_schema, remain: config.limit, file_opener, @@ -86,9 +109,16 @@ impl FileStream { file_stream_metrics: FileStreamMetrics::new(metrics, partition), baseline_metrics: BaselineMetrics::new(metrics, partition), on_error: OnError::Fail, + morsel_guard: None, }) } + /// Set the shared work queue for morsel-driven execution. + pub fn with_shared_queue(mut self, queue: Arc) -> Self { + self.shared_queue = Some(queue); + self + } + /// Specify the behavior when an error occurs opening or scanning a file /// /// If `OnError::Skip` the stream will skip files which encounter an error and continue @@ -102,7 +132,16 @@ impl FileStream { /// /// Since file opening is mostly IO (and may involve a /// bunch of sequential IO), it can be parallelized with decoding. + /// + /// In morsel-driven mode this prefetches the next already-morselized item + /// from the shared queue (leaf morsels only — items that still need + /// async morselization are left in the queue for the normal Idle → + /// Morselizing path). fn start_next_file(&mut self) -> Option> { + if self.shared_queue.is_some() { + // In morsel-driven don't "prefetch" + return None; + } let part_file = self.file_iter.pop_front()?; Some(self.file_opener.open(part_file)) } @@ -113,15 +152,94 @@ impl FileStream { FileStreamState::Idle => { self.file_stream_metrics.time_opening.start(); - match self.start_next_file().transpose() { - Ok(Some(future)) => self.state = FileStreamState::Open { future }, - Ok(None) => return Poll::Ready(None), + if let Some(queue) = self.shared_queue.as_ref() { + match queue.pull() { + WorkStatus::Work(part_file) => { + if self.file_opener.is_leaf_morsel(&part_file) { + // Leaf morsel from the morsel queue — open directly. + match self.file_opener.open(part_file) { + Ok(future) => { + self.state = FileStreamState::Open { future } + } + Err(e) => { + self.file_stream_metrics.time_opening.stop(); + self.state = FileStreamState::Error; + return Poll::Ready(Some(Err(e))); + } + } + } else { + // Whole file from the file queue — morselize it. + self.morsel_guard = Some(MorselizingGuard { + queue: Arc::clone(queue), + }); + self.state = FileStreamState::Morselizing { + future: self.file_opener.morselize(part_file), + }; + } + } + WorkStatus::Wait => { + self.file_stream_metrics.time_opening.stop(); + let queue_captured = Arc::clone(queue); + self.state = FileStreamState::Waiting { + future: Box::pin(async move { + let notified = queue_captured.notify.notified(); + if !queue_captured.has_work_or_done() { + notified.await; + } + }), + }; + } + WorkStatus::Done => { + self.file_stream_metrics.time_opening.stop(); + return Poll::Ready(None); + } + } + } else { + match self.start_next_file().transpose() { + Ok(Some(future)) => { + self.state = FileStreamState::Open { future } + } + Ok(None) => return Poll::Ready(None), + Err(e) => { + self.state = FileStreamState::Error; + return Poll::Ready(Some(Err(e))); + } + } + } + } + FileStreamState::Morselizing { future } => { + match ready!(future.poll_unpin(cx)) { + Ok(morsels) => { + let queue = self.shared_queue.as_ref().expect("shared queue"); + // Take the guard to decrement morselizing_count + let _guard = self.morsel_guard.take(); + + if morsels.is_empty() { + self.file_stream_metrics.time_opening.stop(); + // No morsels returned, skip this file + self.state = FileStreamState::Idle; + } else { + // Push morsels to the morsel queue. Workers + // drain that queue before pulling new files, + // so these row groups get processed next, + // preserving I/O locality within the file. + queue.push_morsels(morsels); + self.file_stream_metrics.time_opening.stop(); + self.state = FileStreamState::Idle; + } + } Err(e) => { + let _guard = self.morsel_guard.take(); + self.file_stream_metrics.time_opening.stop(); self.state = FileStreamState::Error; return Poll::Ready(Some(Err(e))); } } } + FileStreamState::Waiting { future } => { + ready!(future.poll_unpin(cx)); + self.state = FileStreamState::Idle; + } FileStreamState::Open { future } => match ready!(future.poll_unpin(cx)) { Ok(reader) => { // include time needed to start opening in `start_next_file` @@ -214,7 +332,13 @@ impl FileStream { } } } - None => return Poll::Ready(None), + None => { + if self.shared_queue.is_some() { + self.state = FileStreamState::Idle; + } else { + return Poll::Ready(None); + } + } }, OnError::Fail => { self.state = FileStreamState::Error; @@ -243,7 +367,13 @@ impl FileStream { } } } - None => return Poll::Ready(None), + None => { + if self.shared_queue.is_some() { + self.state = FileStreamState::Idle; + } else { + return Poll::Ready(None); + } + } } } } @@ -276,6 +406,109 @@ impl RecordBatchStream for FileStream { } } +/// Result of pulling work from the queue +#[derive(Debug)] +pub enum WorkStatus { + /// A morsel is available + Work(PartitionedFile), + /// No morsel available now, but others are morselizing + Wait, + /// No more work available + Done, +} + +/// A shared queue of [`PartitionedFile`] morsels for morsel-driven execution. +/// +/// Internally keeps two queues: one for whole files that still need +/// morselizing and one for already-morselized leaf morsels (e.g. row +/// groups). Workers drain the morsel queue first, which keeps I/O +/// sequential within a file because freshly produced morsels are +/// consumed before the next file is opened. +#[derive(Debug)] +pub struct WorkQueue { + /// Whole files waiting to be morselized. + files: Mutex>, + /// Already-morselized leaf morsels ready to be opened directly. + morsels: Mutex>, + /// Number of workers currently morselizing a file. + morselizing_count: AtomicUsize, + /// Notify waiters when work is added or morselizing finishes. + notify: Notify, +} + +impl WorkQueue { + /// Create a new `WorkQueue` with the given initial files. + pub fn new(initial_files: Vec) -> Self { + Self { + files: Mutex::new(VecDeque::from(initial_files)), + morsels: Mutex::new(VecDeque::new()), + morselizing_count: AtomicUsize::new(0), + notify: Notify::new(), + } + } + + /// Pull a work item from the queue. + /// + /// Prefers already-morselized morsels (for I/O locality) over whole + /// files that still need morselizing. + pub fn pull(&self) -> WorkStatus { + // First try the morsel queue — these are ready to open immediately + // and preserve locality with the file that was just morselized. + if let Some(morsel) = self.morsels.lock().unwrap().pop_front() { + return WorkStatus::Work(morsel); + } + // Fall back to whole files that need morselizing. + let mut files = self.files.lock().unwrap(); + if let Some(file) = files.pop_front() { + // Relaxed: the increment is done by the same task that will later call + // stop_morselizing(), so program order ensures the decrement sees it. + self.morselizing_count.fetch_add(1, Ordering::Relaxed); + WorkStatus::Work(file) + } else if self.morselizing_count.load(Ordering::Acquire) > 0 { + // Acquire: stop_morselizing() uses AcqRel (a Release write) without + // holding the files mutex, so we need Acquire here to synchronize with + // it on weakly-ordered architectures (e.g. ARM). + WorkStatus::Wait + } else { + // Check the morsel queue one more time — a morselizer may have + // pushed work between our first check and reaching this point. + if self.morsels.lock().unwrap().is_empty() { + WorkStatus::Done + } else { + WorkStatus::Wait + } + } + } + + /// Returns true if there is work in either queue or if all morselizing is done. + pub fn has_work_or_done(&self) -> bool { + !self.morsels.lock().unwrap().is_empty() + || !self.files.lock().unwrap().is_empty() + || self.morselizing_count.load(Ordering::Acquire) == 0 + } + + /// Push morselized leaf morsels to the morsel queue. + pub fn push_morsels(&self, morsels: Vec) { + if morsels.is_empty() { + return; + } + self.morsels.lock().unwrap().extend(morsels); + self.notify.notify_waiters(); + } + + /// Decrement the morselizing count. Notifies waiting workers only when the + /// count reaches zero, since that is the point at which they may need to + /// re-evaluate whether all work is done. When count is still > 0, any new + /// morsels pushed to the queue already triggered a notification via + /// `push_morsels`, so no additional wakeup is needed here. + pub fn stop_morselizing(&self) { + let prev = self.morselizing_count.fetch_sub(1, Ordering::AcqRel); + if prev == 1 { + self.notify.notify_waiters(); + } + } +} + /// A fallible future that resolves to a stream of [`RecordBatch`] pub type FileOpenFuture = BoxFuture<'static, Result>>>; @@ -298,6 +531,29 @@ pub trait FileOpener: Unpin + Send + Sync { /// Asynchronously open the specified file and return a stream /// of [`RecordBatch`] fn open(&self, partitioned_file: PartitionedFile) -> Result; + + /// Optional: Split a file into smaller morsels for morsel-driven execution. + /// + /// By default, returns the file as a single morsel. + fn morselize( + &self, + file: PartitionedFile, + ) -> BoxFuture<'static, Result>> { + Box::pin(futures::future::ready(Ok(vec![file]))) + } + + /// Returns `true` if `file` is already a leaf morsel that can be opened + /// directly without going through [`Self::morselize`]. + /// + /// Returning `true` allows the [`FileStream`] to skip the async + /// `Morselizing` state and go straight to `Open`, and to prefetch the next + /// morsel while scanning the current one. + /// + /// The default implementation returns `false` (conservative — always + /// morselize). + fn is_leaf_morsel(&self, _file: &PartitionedFile) -> bool { + false + } } /// Represents the state of the next `FileOpenFuture`. Since we need to poll @@ -317,6 +573,16 @@ pub enum FileStreamState { /// A [`FileOpenFuture`] returned by [`FileOpener::open`] future: FileOpenFuture, }, + /// Currently splitting a file into smaller morsels. + Morselizing { + /// A future that resolves to a list of morsels + future: BoxFuture<'static, Result>>, + }, + /// Waiting for more work to be added to the queue. + Waiting { + /// A future that resolves when more work is available + future: BoxFuture<'static, ()>, + }, /// Scanning the [`BoxStream`] returned by the completion of a [`FileOpenFuture`] /// returned by [`FileOpener::open`] Scan { diff --git a/datafusion/datasource/src/source.rs b/datafusion/datasource/src/source.rs index 05028ed0f4683..0db0b38baadb7 100644 --- a/datafusion/datasource/src/source.rs +++ b/datafusion/datasource/src/source.rs @@ -20,7 +20,9 @@ use std::any::Any; use std::fmt; use std::fmt::{Debug, Formatter}; +use std::pin::Pin; use std::sync::Arc; +use std::task::{Context, Poll}; use datafusion_physical_expr::projection::ProjectionExprs; use datafusion_physical_plan::execution_plan::{ @@ -36,15 +38,19 @@ use datafusion_physical_plan::{ use itertools::Itertools; use crate::file_scan_config::FileScanConfig; +use crate::file_stream::WorkQueue; +use arrow::datatypes::SchemaRef; +use arrow::record_batch::RecordBatch; use datafusion_common::config::ConfigOptions; use datafusion_common::{Constraints, Result, Statistics}; -use datafusion_execution::{SendableRecordBatchStream, TaskContext}; +use datafusion_execution::{RecordBatchStream, SendableRecordBatchStream, TaskContext}; use datafusion_physical_expr::{EquivalenceProperties, Partitioning, PhysicalExpr}; use datafusion_physical_expr_common::sort_expr::{LexOrdering, PhysicalSortExpr}; use datafusion_physical_plan::SortOrderPushdownResult; use datafusion_physical_plan::filter_pushdown::{ ChildPushdownResult, FilterPushdownPhase, FilterPushdownPropagation, PushedDown, }; +use futures::Stream; /// A source of data, typically a list of files or memory /// @@ -125,6 +131,7 @@ pub trait DataSource: Send + Sync + Debug { partition: usize, context: Arc, ) -> Result; + fn as_any(&self) -> &dyn Any; /// Format this source for display in explain plans fn fmt_as(&self, t: DisplayFormatType, f: &mut Formatter) -> fmt::Result; @@ -300,18 +307,42 @@ impl ExecutionPlan for DataSourceExec { partition: usize, context: Arc, ) -> Result { - let stream = self.data_source.open(partition, Arc::clone(&context))?; + let morsel_config = self + .data_source + .as_any() + .downcast_ref::() + .filter(|c| c.morsel_driven); + + let (stream, queue) = if let Some(config) = morsel_config { + let key = Arc::as_ptr(&self.data_source) as *const () as usize; + let queue = context.get_or_insert_shared_state(key, || { + let all_files = config + .file_groups + .iter() + .flat_map(|g| g.files().iter().cloned()) + .collect(); + WorkQueue::new(all_files) + }); + let stream = + config.open_with_queue(partition, &context, Some(Arc::clone(&queue)))?; + (stream, Some(queue)) + } else { + ( + self.data_source.open(partition, Arc::clone(&context))?, + None, + ) + }; + let batch_size = context.session_config().batch_size(); log::debug!( "Batch splitting enabled for partition {partition}: batch_size={batch_size}" ); let metrics = self.data_source.metrics(); let split_metrics = SplitMetrics::new(&metrics, partition); - Ok(Box::pin(BatchSplitStream::new( - stream, - batch_size, - split_metrics, - ))) + Ok(Box::pin(DataSourceExecStream { + inner: Box::pin(BatchSplitStream::new(stream, batch_size, split_metrics)), + _shared_queue: queue, + })) } fn metrics(&self) -> Option { @@ -409,6 +440,30 @@ impl ExecutionPlan for DataSourceExec { } } +struct DataSourceExecStream { + inner: SendableRecordBatchStream, + /// Holds a strong reference to the morsel queue so it stays alive + /// as long as any partition stream exists. + _shared_queue: Option>, +} + +impl Stream for DataSourceExecStream { + type Item = Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.inner.as_mut().poll_next(cx) + } +} + +impl RecordBatchStream for DataSourceExecStream { + fn schema(&self) -> SchemaRef { + self.inner.schema() + } +} + impl DataSourceExec { pub fn from_data_source(data_source: impl DataSource + 'static) -> Arc { Arc::new(Self::new(Arc::new(data_source))) diff --git a/datafusion/execution/src/task.rs b/datafusion/execution/src/task.rs index 38f31cf4629eb..0f797ffcba303 100644 --- a/datafusion/execution/src/task.rs +++ b/datafusion/execution/src/task.rs @@ -22,9 +22,22 @@ use crate::{ use datafusion_common::{Result, internal_datafusion_err, plan_datafusion_err}; use datafusion_expr::planner::ExprPlanner; use datafusion_expr::{AggregateUDF, ScalarUDF, WindowUDF}; +use std::any::Any; use std::collections::HashSet; +use std::fmt; +use std::sync::Mutex; use std::{collections::HashMap, sync::Arc}; +/// Type-erased shared state map used by execution plan nodes to share +/// state across partitions within the same query execution. +struct SharedState(Mutex>>); + +impl fmt::Debug for SharedState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("SharedState") + } +} + /// Task Execution Context /// /// A [`TaskContext`] contains the state required during a single query's @@ -48,6 +61,10 @@ pub struct TaskContext { window_functions: HashMap>, /// Runtime environment associated with this task context runtime: Arc, + /// Shared state for execution plan nodes within this query execution. + /// Keyed by a caller-chosen identifier (e.g. pointer address of a plan + /// node's `Arc`). + shared_state: SharedState, } impl Default for TaskContext { @@ -63,6 +80,7 @@ impl Default for TaskContext { aggregate_functions: HashMap::new(), window_functions: HashMap::new(), runtime, + shared_state: SharedState(Mutex::new(HashMap::new())), } } } @@ -90,6 +108,7 @@ impl TaskContext { aggregate_functions, window_functions, runtime, + shared_state: SharedState(Mutex::new(HashMap::new())), } } @@ -136,6 +155,27 @@ impl TaskContext { self } + /// Get or create shared state for a given key. + /// + /// Execution plan nodes use this to share state (e.g. work queues) + /// across partitions within the same query execution. The key is + /// typically derived from a stable pointer (e.g. `Arc::as_ptr`). + pub fn get_or_insert_shared_state( + &self, + key: usize, + create: impl FnOnce() -> T, + ) -> Arc { + let mut map = self.shared_state.0.lock().unwrap(); + if let Some(existing) = map.get(&key) { + if let Ok(typed) = Arc::clone(existing).downcast::() { + return typed; + } + } + let value = Arc::new(create()); + map.insert(key, Arc::clone(&value) as Arc); + value + } + /// Update the [`RuntimeEnv`] pub fn with_runtime(mut self, runtime: Arc) -> Self { self.runtime = runtime; diff --git a/datafusion/physical-expr-common/src/physical_expr.rs b/datafusion/physical-expr-common/src/physical_expr.rs index 7107b0a9004d3..a1473c5558054 100644 --- a/datafusion/physical-expr-common/src/physical_expr.rs +++ b/datafusion/physical-expr-common/src/physical_expr.rs @@ -671,6 +671,160 @@ pub fn is_volatile(expr: &Arc) -> bool { is_volatile } +/// A transparent wrapper that marks a [`PhysicalExpr`] as *optional* — i.e., +/// droppable without affecting query correctness. +/// +/// This is used for filters that are performance hints (e.g., dynamic join +/// filters) as opposed to mandatory predicates. The selectivity tracker can +/// detect this wrapper via `expr.as_any().downcast_ref::()` +/// and choose to drop the filter entirely when it is not cost-effective. +/// +/// All [`PhysicalExpr`] methods are delegated to the wrapped inner expression. +/// +/// Currently used by `HashJoinExec` for dynamic join filters. When the +/// selectivity tracker drops such a filter, the join still enforces +/// correctness independently — "dropped" simply means the filter is never +/// applied as a scan-time optimization. +#[derive(Debug)] +pub struct OptionalFilterPhysicalExpr { + inner: Arc, +} + +impl OptionalFilterPhysicalExpr { + /// Create a new optional filter wrapping the given expression. + pub fn new(inner: Arc) -> Self { + Self { inner } + } + + /// Returns a clone of the inner (unwrapped) expression. + pub fn inner(&self) -> Arc { + Arc::clone(&self.inner) + } +} + +impl Display for OptionalFilterPhysicalExpr { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "Optional({})", self.inner) + } +} + +impl PartialEq for OptionalFilterPhysicalExpr { + fn eq(&self, other: &Self) -> bool { + self.inner.as_ref() == other.inner.as_ref() + } +} + +impl Eq for OptionalFilterPhysicalExpr {} + +impl Hash for OptionalFilterPhysicalExpr { + fn hash(&self, state: &mut H) { + self.inner.as_ref().hash(state); + } +} + +impl PhysicalExpr for OptionalFilterPhysicalExpr { + fn as_any(&self) -> &dyn Any { + self + } + + fn data_type(&self, input_schema: &Schema) -> Result { + self.inner.data_type(input_schema) + } + + fn nullable(&self, input_schema: &Schema) -> Result { + self.inner.nullable(input_schema) + } + + fn evaluate(&self, batch: &RecordBatch) -> Result { + self.inner.evaluate(batch) + } + + fn return_field(&self, input_schema: &Schema) -> Result { + self.inner.return_field(input_schema) + } + + fn evaluate_selection( + &self, + batch: &RecordBatch, + selection: &BooleanArray, + ) -> Result { + self.inner.evaluate_selection(batch, selection) + } + + fn children(&self) -> Vec<&Arc> { + vec![&self.inner] + } + + fn with_new_children( + self: Arc, + children: Vec>, + ) -> Result> { + assert_eq_or_internal_err!( + children.len(), + 1, + "OptionalFilterPhysicalExpr: expected 1 child" + ); + Ok(Arc::new(OptionalFilterPhysicalExpr::new(Arc::clone( + &children[0], + )))) + } + + fn evaluate_bounds(&self, children: &[&Interval]) -> Result { + self.inner.evaluate_bounds(children) + } + + fn propagate_constraints( + &self, + interval: &Interval, + children: &[&Interval], + ) -> Result>> { + self.inner.propagate_constraints(interval, children) + } + + fn evaluate_statistics(&self, children: &[&Distribution]) -> Result { + self.inner.evaluate_statistics(children) + } + + fn propagate_statistics( + &self, + parent: &Distribution, + children: &[&Distribution], + ) -> Result>> { + self.inner.propagate_statistics(parent, children) + } + + fn get_properties(&self, children: &[ExprProperties]) -> Result { + self.inner.get_properties(children) + } + + fn fmt_sql(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.inner.fmt_sql(f) + } + + fn snapshot(&self) -> Result>> { + // Always unwrap the Optional wrapper for snapshot consumers (e.g. PruningPredicate). + // If inner has a snapshot, use it; otherwise return the inner directly. + Ok(Some(match self.inner.snapshot()? { + Some(snap) => snap, + None => Arc::clone(&self.inner), + })) + } + + fn snapshot_generation(&self) -> u64 { + // The wrapper itself is not dynamic; tree-walking picks up + // inner's generation via children(). + 0 + } + + fn is_volatile_node(&self) -> bool { + self.inner.is_volatile_node() + } + + fn placement(&self) -> ExpressionPlacement { + self.inner.placement() + } +} + #[cfg(test)] mod test { use crate::physical_expr::PhysicalExpr; @@ -678,6 +832,7 @@ mod test { use arrow::datatypes::{DataType, Schema}; use datafusion_expr_common::columnar_value::ColumnarValue; use std::fmt::{Display, Formatter}; + use std::hash::{Hash, Hasher}; use std::sync::Arc; #[derive(Debug, PartialEq, Eq, Hash)] @@ -856,4 +1011,111 @@ mod test { &BooleanArray::from(vec![true; 5]), ); } + + #[test] + fn test_optional_filter_downcast() { + use super::OptionalFilterPhysicalExpr; + + let inner: Arc = Arc::new(TestExpr {}); + let optional = Arc::new(OptionalFilterPhysicalExpr::new(Arc::clone(&inner))); + + // Can downcast to detect the wrapper + let as_physical: Arc = optional; + assert!( + as_physical + .as_any() + .downcast_ref::() + .is_some() + ); + + // Inner expr is NOT detectable as optional + assert!( + inner + .as_any() + .downcast_ref::() + .is_none() + ); + } + + #[test] + fn test_optional_filter_delegates_evaluate() { + use super::OptionalFilterPhysicalExpr; + + let inner: Arc = Arc::new(TestExpr {}); + let optional = OptionalFilterPhysicalExpr::new(Arc::clone(&inner)); + + let batch = + unsafe { RecordBatch::new_unchecked(Arc::new(Schema::empty()), vec![], 5) }; + let result = optional.evaluate(&batch).unwrap(); + let array = result.to_array(5).unwrap(); + assert_eq!(array.len(), 5); + } + + #[test] + fn test_optional_filter_children_and_with_new_children() { + use super::OptionalFilterPhysicalExpr; + + let inner: Arc = Arc::new(TestExpr {}); + let optional = Arc::new(OptionalFilterPhysicalExpr::new(Arc::clone(&inner))); + + // children() returns the inner + let children = optional.children(); + assert_eq!(children.len(), 1); + + // with_new_children preserves the wrapper + let new_inner: Arc = Arc::new(TestExpr {}); + let rewrapped = Arc::clone(&optional) + .with_new_children(vec![new_inner]) + .unwrap(); + assert!( + rewrapped + .as_any() + .downcast_ref::() + .is_some() + ); + } + + #[test] + fn test_optional_filter_inner() { + use super::OptionalFilterPhysicalExpr; + + let inner: Arc = Arc::new(TestExpr {}); + let optional = OptionalFilterPhysicalExpr::new(Arc::clone(&inner)); + + // inner() returns a clone of the wrapped expression + let unwrapped = optional.inner(); + assert!(unwrapped.as_any().downcast_ref::().is_some()); + } + + #[test] + fn test_optional_filter_snapshot_generation_zero() { + use super::OptionalFilterPhysicalExpr; + + let inner: Arc = Arc::new(TestExpr {}); + let optional = OptionalFilterPhysicalExpr::new(inner); + + assert_eq!(optional.snapshot_generation(), 0); + } + + #[test] + fn test_optional_filter_eq_hash() { + use super::OptionalFilterPhysicalExpr; + use std::collections::hash_map::DefaultHasher; + + let inner1: Arc = Arc::new(TestExpr {}); + let inner2: Arc = Arc::new(TestExpr {}); + + let opt1 = OptionalFilterPhysicalExpr::new(inner1); + let opt2 = OptionalFilterPhysicalExpr::new(inner2); + + // Same inner type → equal + assert_eq!(opt1, opt2); + + // Same hash + let mut h1 = DefaultHasher::new(); + let mut h2 = DefaultHasher::new(); + opt1.hash(&mut h1); + opt2.hash(&mut h2); + assert_eq!(h1.finish(), h2.finish()); + } } diff --git a/datafusion/physical-expr/src/simplifier/mod.rs b/datafusion/physical-expr/src/simplifier/mod.rs index 3f3f8573449eb..38663f1b06609 100644 --- a/datafusion/physical-expr/src/simplifier/mod.rs +++ b/datafusion/physical-expr/src/simplifier/mod.rs @@ -61,7 +61,10 @@ impl<'a> PhysicalExprSimplifier<'a> { count += 1; let result = current_expr.transform(|node| { #[cfg(debug_assertions)] - let original_type = node.data_type(schema).unwrap(); + // Use `ok()` to skip the assertion when data_type fails (e.g., for + // DynamicFilterPhysicalExpr whose inner expression may reference columns + // outside the provided schema when the filter has been updated concurrently). + let original_type = node.data_type(schema).ok(); // Apply NOT expression simplification first, then unwrap cast optimization, // then constant expression evaluation @@ -73,11 +76,14 @@ impl<'a> PhysicalExprSimplifier<'a> { })?; #[cfg(debug_assertions)] - assert_eq!( - rewritten.data.data_type(schema).unwrap(), - original_type, - "Simplified expression should have the same data type as the original" - ); + if let Some(original_type) = original_type + && let Ok(rewritten_type) = rewritten.data.data_type(schema) { + assert_eq!( + rewritten_type, + original_type, + "Simplified expression should have the same data type as the original" + ); + } Ok(rewritten) })?; diff --git a/datafusion/physical-expr/src/utils/guarantee.rs b/datafusion/physical-expr/src/utils/guarantee.rs index c4ce74fd3a573..70c83cee65b74 100644 --- a/datafusion/physical-expr/src/utils/guarantee.rs +++ b/datafusion/physical-expr/src/utils/guarantee.rs @@ -389,6 +389,9 @@ impl<'a> ColOpLit<'a> { /// 2. `literal col` /// 3. operator is `=` or `!=` /// + /// Also handles `CastColumnExpr(col) literal` patterns where the + /// column is wrapped in a cast (e.g., from schema adaptation). + /// /// Returns None otherwise fn try_new(expr: &'a Arc) -> Option { let binary_expr = expr @@ -405,9 +408,9 @@ impl<'a> ColOpLit<'a> { Operator::NotEq => Guarantee::NotIn, _ => return None, }; - // col literal + // col literal (also handles CastColumnExpr(col) literal) if let (Some(col), Some(lit)) = ( - left.downcast_ref::(), + extract_column(binary_expr.left()), right.downcast_ref::(), ) { Some(Self { @@ -416,10 +419,10 @@ impl<'a> ColOpLit<'a> { lit, }) } - // literal col + // literal col (also handles literal CastColumnExpr(col)) else if let (Some(lit), Some(col)) = ( left.downcast_ref::(), - right.downcast_ref::(), + extract_column(binary_expr.right()), ) { Some(Self { col, @@ -432,6 +435,25 @@ impl<'a> ColOpLit<'a> { } } +/// Extracts a [`Column`](crate::expressions::Column) reference from a physical +/// expression, looking through [`CastColumnExpr`](crate::expressions::CastColumnExpr) +/// wrappers. +fn extract_column(expr: &Arc) -> Option<&crate::expressions::Column> { + if let Some(col) = expr.as_any().downcast_ref::() { + return Some(col); + } + if let Some(cast) = expr + .as_any() + .downcast_ref::() + { + return cast + .expr() + .as_any() + .downcast_ref::(); + } + None +} + /// Represents a single `col [not]in literal` expression struct ColInList<'a> { col: &'a crate::expressions::Column, diff --git a/datafusion/physical-plan/src/joins/hash_join/exec.rs b/datafusion/physical-plan/src/joins/hash_join/exec.rs index eda7e93effa2c..48478a033ae7d 100644 --- a/datafusion/physical-plan/src/joins/hash_join/exec.rs +++ b/datafusion/physical-plan/src/joins/hash_join/exec.rs @@ -86,7 +86,9 @@ use datafusion_physical_expr::projection::{ProjectionRef, combine_projections}; use datafusion_physical_expr::{PhysicalExpr, PhysicalExprRef}; use ahash::RandomState; -use datafusion_physical_expr_common::physical_expr::fmt_sql; +use datafusion_physical_expr_common::physical_expr::{ + OptionalFilterPhysicalExpr, fmt_sql, +}; use datafusion_physical_expr_common::utils::evaluate_expressions_to_arrays; use futures::TryStreamExt; use parking_lot::Mutex; @@ -1591,9 +1593,12 @@ impl ExecutionPlan for HashJoinExec { if phase == FilterPushdownPhase::Post && self.allow_join_dynamic_filter_pushdown(config) { - // Add actual dynamic filter to right side (probe side) + // Add actual dynamic filter to right side (probe side), + // wrapped as optional so it can be dropped if ineffective. let dynamic_filter = Self::create_dynamic_filter(&self.on); - right_child = right_child.with_self_filter(dynamic_filter); + let wrapped: Arc = + Arc::new(OptionalFilterPhysicalExpr::new(dynamic_filter)); + right_child = right_child.with_self_filter(wrapped); } Ok(FilterDescription::new() @@ -1615,8 +1620,13 @@ impl ExecutionPlan for HashJoinExec { // Note that we don't check PushdDownPredicate::discrimnant because even if nothing said // "yes, I can fully evaluate this filter" things might still use it for statistics -> it's worth updating let predicate = Arc::clone(&filter.predicate); - if let Ok(dynamic_filter) = - Arc::downcast::(predicate) + // Unwrap OptionalFilterPhysicalExpr if present to get the inner DynamicFilterPhysicalExpr + let inner = predicate + .as_any() + .downcast_ref::() + .map(|opt| opt.inner()) + .unwrap_or(predicate); + if let Ok(dynamic_filter) = Arc::downcast::(inner) { // We successfully pushed down our self filter - we need to make a new node with the dynamic filter let new_node = self diff --git a/datafusion/proto-common/proto/datafusion_common.proto b/datafusion/proto-common/proto/datafusion_common.proto index 62c6bbe85612a..e8787ce7367b1 100644 --- a/datafusion/proto-common/proto/datafusion_common.proto +++ b/datafusion/proto-common/proto/datafusion_common.proto @@ -535,7 +535,7 @@ message ParquetOptions { bool pruning = 2; // default = true bool skip_metadata = 3; // default = true bool pushdown_filters = 5; // default = false - bool reorder_filters = 6; // default = false + reserved 6; // was reorder_filters bool force_filter_selections = 34; // default = false uint64 data_pagesize_limit = 7; // default = 1024 * 1024 uint64 write_batch_size = 8; // default = 1024 @@ -549,6 +549,7 @@ message ParquetOptions { bool schema_force_view_types = 28; // default = false bool binary_as_string = 29; // default = false bool skip_arrow_metadata = 30; // default = false + bool allow_morsel_driven = 35; // default = true oneof metadata_size_hint_opt { uint64 metadata_size_hint = 4; @@ -603,6 +604,21 @@ message ParquetOptions { oneof max_predicate_cache_size_opt { uint64 max_predicate_cache_size = 33; } + + oneof filter_pushdown_min_bytes_per_sec_opt { + double filter_pushdown_min_bytes_per_sec = 42; + } + + // field 36 removed (filter_correlation_threshold) + // fields 37-39 removed (filter_statistics_collection_min_rows, fraction, max_rows) + + oneof filter_collecting_byte_ratio_threshold_opt { + double filter_collecting_byte_ratio_threshold = 40; + } + + oneof filter_confidence_z_opt { + double filter_confidence_z = 41; + } } enum JoinSide { diff --git a/datafusion/proto-common/src/from_proto/mod.rs b/datafusion/proto-common/src/from_proto/mod.rs index ca8a269958d73..e29180257ea12 100644 --- a/datafusion/proto-common/src/from_proto/mod.rs +++ b/datafusion/proto-common/src/from_proto/mod.rs @@ -1024,7 +1024,7 @@ impl TryFrom<&protobuf::ParquetOptions> for ParquetOptions { }) .unwrap_or(None), pushdown_filters: value.pushdown_filters, - reorder_filters: value.reorder_filters, + force_filter_selections: value.force_filter_selections, data_pagesize_limit: value.data_pagesize_limit as usize, write_batch_size: value.write_batch_size as usize, @@ -1090,6 +1090,16 @@ impl TryFrom<&protobuf::ParquetOptions> for ParquetOptions { max_predicate_cache_size: value.max_predicate_cache_size_opt.map(|opt| match opt { protobuf::parquet_options::MaxPredicateCacheSizeOpt::MaxPredicateCacheSize(v) => Some(v as usize), }).unwrap_or(None), + allow_morsel_driven: value.allow_morsel_driven, + filter_pushdown_min_bytes_per_sec: value.filter_pushdown_min_bytes_per_sec_opt.map(|opt| match opt { + protobuf::parquet_options::FilterPushdownMinBytesPerSecOpt::FilterPushdownMinBytesPerSec(v) => v, + }).unwrap_or(f64::INFINITY), + filter_collecting_byte_ratio_threshold: value.filter_collecting_byte_ratio_threshold_opt.map(|opt| match opt { + protobuf::parquet_options::FilterCollectingByteRatioThresholdOpt::FilterCollectingByteRatioThreshold(v) => v, + }).unwrap_or(0.2), + filter_confidence_z: value.filter_confidence_z_opt.map(|opt| match opt { + protobuf::parquet_options::FilterConfidenceZOpt::FilterConfidenceZ(v) => v, + }).unwrap_or(2.0), }) } } diff --git a/datafusion/proto-common/src/generated/pbjson.rs b/datafusion/proto-common/src/generated/pbjson.rs index b00e7546bba20..932e308c803e7 100644 --- a/datafusion/proto-common/src/generated/pbjson.rs +++ b/datafusion/proto-common/src/generated/pbjson.rs @@ -5644,9 +5644,7 @@ impl serde::Serialize for ParquetOptions { if self.pushdown_filters { len += 1; } - if self.reorder_filters { - len += 1; - } + if self.force_filter_selections { len += 1; } @@ -5683,6 +5681,9 @@ impl serde::Serialize for ParquetOptions { if self.skip_arrow_metadata { len += 1; } + if self.allow_morsel_driven { + len += 1; + } if self.dictionary_page_size_limit != 0 { len += 1; } @@ -5728,6 +5729,15 @@ impl serde::Serialize for ParquetOptions { if self.max_predicate_cache_size_opt.is_some() { len += 1; } + if self.filter_pushdown_min_bytes_per_sec_opt.is_some() { + len += 1; + } + if self.filter_collecting_byte_ratio_threshold_opt.is_some() { + len += 1; + } + if self.filter_confidence_z_opt.is_some() { + len += 1; + } let mut struct_ser = serializer.serialize_struct("datafusion_common.ParquetOptions", len)?; if self.enable_page_index { struct_ser.serialize_field("enablePageIndex", &self.enable_page_index)?; @@ -5741,9 +5751,7 @@ impl serde::Serialize for ParquetOptions { if self.pushdown_filters { struct_ser.serialize_field("pushdownFilters", &self.pushdown_filters)?; } - if self.reorder_filters { - struct_ser.serialize_field("reorderFilters", &self.reorder_filters)?; - } + if self.force_filter_selections { struct_ser.serialize_field("forceFilterSelections", &self.force_filter_selections)?; } @@ -5788,6 +5796,9 @@ impl serde::Serialize for ParquetOptions { if self.skip_arrow_metadata { struct_ser.serialize_field("skipArrowMetadata", &self.skip_arrow_metadata)?; } + if self.allow_morsel_driven { + struct_ser.serialize_field("allowMorselDriven", &self.allow_morsel_driven)?; + } if self.dictionary_page_size_limit != 0 { #[allow(clippy::needless_borrow)] #[allow(clippy::needless_borrows_for_generic_args)] @@ -5893,6 +5904,27 @@ impl serde::Serialize for ParquetOptions { } } } + if let Some(v) = self.filter_pushdown_min_bytes_per_sec_opt.as_ref() { + match v { + parquet_options::FilterPushdownMinBytesPerSecOpt::FilterPushdownMinBytesPerSec(v) => { + struct_ser.serialize_field("filterPushdownMinBytesPerSec", v)?; + } + } + } + if let Some(v) = self.filter_collecting_byte_ratio_threshold_opt.as_ref() { + match v { + parquet_options::FilterCollectingByteRatioThresholdOpt::FilterCollectingByteRatioThreshold(v) => { + struct_ser.serialize_field("filterCollectingByteRatioThreshold", v)?; + } + } + } + if let Some(v) = self.filter_confidence_z_opt.as_ref() { + match v { + parquet_options::FilterConfidenceZOpt::FilterConfidenceZ(v) => { + struct_ser.serialize_field("filterConfidenceZ", v)?; + } + } + } struct_ser.end() } } @@ -5910,8 +5942,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { "skipMetadata", "pushdown_filters", "pushdownFilters", - "reorder_filters", - "reorderFilters", + "force_filter_selections", "forceFilterSelections", "data_pagesize_limit", @@ -5936,6 +5967,8 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { "binaryAsString", "skip_arrow_metadata", "skipArrowMetadata", + "allow_morsel_driven", + "allowMorselDriven", "dictionary_page_size_limit", "dictionaryPageSizeLimit", "data_page_row_count_limit", @@ -5964,6 +5997,12 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { "coerceInt96", "max_predicate_cache_size", "maxPredicateCacheSize", + "filter_pushdown_min_bytes_per_sec", + "filterPushdownMinBytesPerSec", + "filter_collecting_byte_ratio_threshold", + "filterCollectingByteRatioThreshold", + "filter_confidence_z", + "filterConfidenceZ", ]; #[allow(clippy::enum_variant_names)] @@ -5972,7 +6011,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { Pruning, SkipMetadata, PushdownFilters, - ReorderFilters, + ForceFilterSelections, DataPagesizeLimit, WriteBatchSize, @@ -5985,6 +6024,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { SchemaForceViewTypes, BinaryAsString, SkipArrowMetadata, + AllowMorselDriven, DictionaryPageSizeLimit, DataPageRowCountLimit, MaxRowGroupSize, @@ -6000,6 +6040,9 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { BloomFilterNdv, CoerceInt96, MaxPredicateCacheSize, + FilterPushdownMinBytesPerSec, + FilterCollectingByteRatioThreshold, + FilterConfidenceZ, } impl<'de> serde::Deserialize<'de> for GeneratedField { fn deserialize(deserializer: D) -> std::result::Result @@ -6025,7 +6068,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { "pruning" => Ok(GeneratedField::Pruning), "skipMetadata" | "skip_metadata" => Ok(GeneratedField::SkipMetadata), "pushdownFilters" | "pushdown_filters" => Ok(GeneratedField::PushdownFilters), - "reorderFilters" | "reorder_filters" => Ok(GeneratedField::ReorderFilters), + "forceFilterSelections" | "force_filter_selections" => Ok(GeneratedField::ForceFilterSelections), "dataPagesizeLimit" | "data_pagesize_limit" => Ok(GeneratedField::DataPagesizeLimit), "writeBatchSize" | "write_batch_size" => Ok(GeneratedField::WriteBatchSize), @@ -6038,6 +6081,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { "schemaForceViewTypes" | "schema_force_view_types" => Ok(GeneratedField::SchemaForceViewTypes), "binaryAsString" | "binary_as_string" => Ok(GeneratedField::BinaryAsString), "skipArrowMetadata" | "skip_arrow_metadata" => Ok(GeneratedField::SkipArrowMetadata), + "allowMorselDriven" | "allow_morsel_driven" => Ok(GeneratedField::AllowMorselDriven), "dictionaryPageSizeLimit" | "dictionary_page_size_limit" => Ok(GeneratedField::DictionaryPageSizeLimit), "dataPageRowCountLimit" | "data_page_row_count_limit" => Ok(GeneratedField::DataPageRowCountLimit), "maxRowGroupSize" | "max_row_group_size" => Ok(GeneratedField::MaxRowGroupSize), @@ -6053,6 +6097,9 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { "bloomFilterNdv" | "bloom_filter_ndv" => Ok(GeneratedField::BloomFilterNdv), "coerceInt96" | "coerce_int96" => Ok(GeneratedField::CoerceInt96), "maxPredicateCacheSize" | "max_predicate_cache_size" => Ok(GeneratedField::MaxPredicateCacheSize), + "filterPushdownMinBytesPerSec" | "filter_pushdown_min_bytes_per_sec" => Ok(GeneratedField::FilterPushdownMinBytesPerSec), + "filterCollectingByteRatioThreshold" | "filter_collecting_byte_ratio_threshold" => Ok(GeneratedField::FilterCollectingByteRatioThreshold), + "filterConfidenceZ" | "filter_confidence_z" => Ok(GeneratedField::FilterConfidenceZ), _ => Err(serde::de::Error::unknown_field(value, FIELDS)), } } @@ -6076,7 +6123,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { let mut pruning__ = None; let mut skip_metadata__ = None; let mut pushdown_filters__ = None; - let mut reorder_filters__ = None; + let mut force_filter_selections__ = None; let mut data_pagesize_limit__ = None; let mut write_batch_size__ = None; @@ -6089,6 +6136,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { let mut schema_force_view_types__ = None; let mut binary_as_string__ = None; let mut skip_arrow_metadata__ = None; + let mut allow_morsel_driven__ = None; let mut dictionary_page_size_limit__ = None; let mut data_page_row_count_limit__ = None; let mut max_row_group_size__ = None; @@ -6104,6 +6152,9 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { let mut bloom_filter_ndv_opt__ = None; let mut coerce_int96_opt__ = None; let mut max_predicate_cache_size_opt__ = None; + let mut filter_pushdown_min_bytes_per_sec_opt__ = None; + let mut filter_collecting_byte_ratio_threshold_opt__ = None; + let mut filter_confidence_z_opt__ = None; while let Some(k) = map_.next_key()? { match k { GeneratedField::EnablePageIndex => { @@ -6130,12 +6181,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { } pushdown_filters__ = Some(map_.next_value()?); } - GeneratedField::ReorderFilters => { - if reorder_filters__.is_some() { - return Err(serde::de::Error::duplicate_field("reorderFilters")); - } - reorder_filters__ = Some(map_.next_value()?); - } + GeneratedField::ForceFilterSelections => { if force_filter_selections__.is_some() { return Err(serde::de::Error::duplicate_field("forceFilterSelections")); @@ -6216,6 +6262,12 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { } skip_arrow_metadata__ = Some(map_.next_value()?); } + GeneratedField::AllowMorselDriven => { + if allow_morsel_driven__.is_some() { + return Err(serde::de::Error::duplicate_field("allowMorselDriven")); + } + allow_morsel_driven__ = Some(map_.next_value()?); + } GeneratedField::DictionaryPageSizeLimit => { if dictionary_page_size_limit__.is_some() { return Err(serde::de::Error::duplicate_field("dictionaryPageSizeLimit")); @@ -6312,6 +6364,24 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { } max_predicate_cache_size_opt__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| parquet_options::MaxPredicateCacheSizeOpt::MaxPredicateCacheSize(x.0)); } + GeneratedField::FilterPushdownMinBytesPerSec => { + if filter_pushdown_min_bytes_per_sec_opt__.is_some() { + return Err(serde::de::Error::duplicate_field("filterPushdownMinBytesPerSec")); + } + filter_pushdown_min_bytes_per_sec_opt__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| parquet_options::FilterPushdownMinBytesPerSecOpt::FilterPushdownMinBytesPerSec(x.0)); + } + GeneratedField::FilterCollectingByteRatioThreshold => { + if filter_collecting_byte_ratio_threshold_opt__.is_some() { + return Err(serde::de::Error::duplicate_field("filterCollectingByteRatioThreshold")); + } + filter_collecting_byte_ratio_threshold_opt__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| parquet_options::FilterCollectingByteRatioThresholdOpt::FilterCollectingByteRatioThreshold(x.0)); + } + GeneratedField::FilterConfidenceZ => { + if filter_confidence_z_opt__.is_some() { + return Err(serde::de::Error::duplicate_field("filterConfidenceZ")); + } + filter_confidence_z_opt__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| parquet_options::FilterConfidenceZOpt::FilterConfidenceZ(x.0)); + } } } Ok(ParquetOptions { @@ -6319,7 +6389,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { pruning: pruning__.unwrap_or_default(), skip_metadata: skip_metadata__.unwrap_or_default(), pushdown_filters: pushdown_filters__.unwrap_or_default(), - reorder_filters: reorder_filters__.unwrap_or_default(), + force_filter_selections: force_filter_selections__.unwrap_or_default(), data_pagesize_limit: data_pagesize_limit__.unwrap_or_default(), write_batch_size: write_batch_size__.unwrap_or_default(), @@ -6332,6 +6402,7 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { schema_force_view_types: schema_force_view_types__.unwrap_or_default(), binary_as_string: binary_as_string__.unwrap_or_default(), skip_arrow_metadata: skip_arrow_metadata__.unwrap_or_default(), + allow_morsel_driven: allow_morsel_driven__.unwrap_or_default(), dictionary_page_size_limit: dictionary_page_size_limit__.unwrap_or_default(), data_page_row_count_limit: data_page_row_count_limit__.unwrap_or_default(), max_row_group_size: max_row_group_size__.unwrap_or_default(), @@ -6347,6 +6418,9 @@ impl<'de> serde::Deserialize<'de> for ParquetOptions { bloom_filter_ndv_opt: bloom_filter_ndv_opt__, coerce_int96_opt: coerce_int96_opt__, max_predicate_cache_size_opt: max_predicate_cache_size_opt__, + filter_pushdown_min_bytes_per_sec_opt: filter_pushdown_min_bytes_per_sec_opt__, + filter_collecting_byte_ratio_threshold_opt: filter_collecting_byte_ratio_threshold_opt__, + filter_confidence_z_opt: filter_confidence_z_opt__, }) } } diff --git a/datafusion/proto-common/src/generated/prost.rs b/datafusion/proto-common/src/generated/prost.rs index a09826a29be52..ca90b28eecbbf 100644 --- a/datafusion/proto-common/src/generated/prost.rs +++ b/datafusion/proto-common/src/generated/prost.rs @@ -789,9 +789,7 @@ pub struct ParquetOptions { /// default = false #[prost(bool, tag = "5")] pub pushdown_filters: bool, - /// default = false - #[prost(bool, tag = "6")] - pub reorder_filters: bool, + /// default = false #[prost(bool, tag = "34")] pub force_filter_selections: bool, @@ -830,6 +828,9 @@ pub struct ParquetOptions { /// default = false #[prost(bool, tag = "30")] pub skip_arrow_metadata: bool, + /// default = true + #[prost(bool, tag = "35")] + pub allow_morsel_driven: bool, #[prost(uint64, tag = "12")] pub dictionary_page_size_limit: u64, #[prost(uint64, tag = "18")] @@ -872,6 +873,24 @@ pub struct ParquetOptions { pub max_predicate_cache_size_opt: ::core::option::Option< parquet_options::MaxPredicateCacheSizeOpt, >, + #[prost(oneof = "parquet_options::FilterPushdownMinBytesPerSecOpt", tags = "42")] + pub filter_pushdown_min_bytes_per_sec_opt: ::core::option::Option< + parquet_options::FilterPushdownMinBytesPerSecOpt, + >, + #[prost( + oneof = "parquet_options::FilterCollectingByteRatioThresholdOpt", + tags = "40" + )] + pub filter_collecting_byte_ratio_threshold_opt: ::core::option::Option< + parquet_options::FilterCollectingByteRatioThresholdOpt, + >, + #[prost( + oneof = "parquet_options::FilterConfidenceZOpt", + tags = "41" + )] + pub filter_confidence_z_opt: ::core::option::Option< + parquet_options::FilterConfidenceZOpt, + >, } /// Nested message and enum types in `ParquetOptions`. pub mod parquet_options { @@ -930,6 +949,21 @@ pub mod parquet_options { #[prost(uint64, tag = "33")] MaxPredicateCacheSize(u64), } + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] + pub enum FilterPushdownMinBytesPerSecOpt { + #[prost(double, tag = "42")] + FilterPushdownMinBytesPerSec(f64), + } + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] + pub enum FilterCollectingByteRatioThresholdOpt { + #[prost(double, tag = "40")] + FilterCollectingByteRatioThreshold(f64), + } + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] + pub enum FilterConfidenceZOpt { + #[prost(double, tag = "41")] + FilterConfidenceZ(f64), + } } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Precision { diff --git a/datafusion/proto-common/src/to_proto/mod.rs b/datafusion/proto-common/src/to_proto/mod.rs index 79e3306a4df1b..39e6eb395c433 100644 --- a/datafusion/proto-common/src/to_proto/mod.rs +++ b/datafusion/proto-common/src/to_proto/mod.rs @@ -877,7 +877,7 @@ impl TryFrom<&ParquetOptions> for protobuf::ParquetOptions { skip_metadata: value.skip_metadata, metadata_size_hint_opt: value.metadata_size_hint.map(|v| protobuf::parquet_options::MetadataSizeHintOpt::MetadataSizeHint(v as u64)), pushdown_filters: value.pushdown_filters, - reorder_filters: value.reorder_filters, + force_filter_selections: value.force_filter_selections, data_pagesize_limit: value.data_pagesize_limit as u64, write_batch_size: value.write_batch_size as u64, @@ -904,6 +904,10 @@ impl TryFrom<&ParquetOptions> for protobuf::ParquetOptions { skip_arrow_metadata: value.skip_arrow_metadata, coerce_int96_opt: value.coerce_int96.clone().map(protobuf::parquet_options::CoerceInt96Opt::CoerceInt96), max_predicate_cache_size_opt: value.max_predicate_cache_size.map(|v| protobuf::parquet_options::MaxPredicateCacheSizeOpt::MaxPredicateCacheSize(v as u64)), + allow_morsel_driven: value.allow_morsel_driven, + filter_pushdown_min_bytes_per_sec_opt: Some(protobuf::parquet_options::FilterPushdownMinBytesPerSecOpt::FilterPushdownMinBytesPerSec(value.filter_pushdown_min_bytes_per_sec)), + filter_collecting_byte_ratio_threshold_opt: Some(protobuf::parquet_options::FilterCollectingByteRatioThresholdOpt::FilterCollectingByteRatioThreshold(value.filter_collecting_byte_ratio_threshold)), + filter_confidence_z_opt: Some(protobuf::parquet_options::FilterConfidenceZOpt::FilterConfidenceZ(value.filter_confidence_z)), }) } } diff --git a/datafusion/proto/src/generated/datafusion_proto_common.rs b/datafusion/proto/src/generated/datafusion_proto_common.rs index a09826a29be52..a059a690bc732 100644 --- a/datafusion/proto/src/generated/datafusion_proto_common.rs +++ b/datafusion/proto/src/generated/datafusion_proto_common.rs @@ -790,9 +790,6 @@ pub struct ParquetOptions { #[prost(bool, tag = "5")] pub pushdown_filters: bool, /// default = false - #[prost(bool, tag = "6")] - pub reorder_filters: bool, - /// default = false #[prost(bool, tag = "34")] pub force_filter_selections: bool, /// default = 1024 * 1024 @@ -830,6 +827,9 @@ pub struct ParquetOptions { /// default = false #[prost(bool, tag = "30")] pub skip_arrow_metadata: bool, + /// default = true + #[prost(bool, tag = "35")] + pub allow_morsel_driven: bool, #[prost(uint64, tag = "12")] pub dictionary_page_size_limit: u64, #[prost(uint64, tag = "18")] @@ -872,6 +872,21 @@ pub struct ParquetOptions { pub max_predicate_cache_size_opt: ::core::option::Option< parquet_options::MaxPredicateCacheSizeOpt, >, + #[prost(oneof = "parquet_options::FilterPushdownMinBytesPerSecOpt", tags = "42")] + pub filter_pushdown_min_bytes_per_sec_opt: ::core::option::Option< + parquet_options::FilterPushdownMinBytesPerSecOpt, + >, + #[prost( + oneof = "parquet_options::FilterCollectingByteRatioThresholdOpt", + tags = "40" + )] + pub filter_collecting_byte_ratio_threshold_opt: ::core::option::Option< + parquet_options::FilterCollectingByteRatioThresholdOpt, + >, + #[prost(oneof = "parquet_options::FilterConfidenceZOpt", tags = "41")] + pub filter_confidence_z_opt: ::core::option::Option< + parquet_options::FilterConfidenceZOpt, + >, } /// Nested message and enum types in `ParquetOptions`. pub mod parquet_options { @@ -930,6 +945,21 @@ pub mod parquet_options { #[prost(uint64, tag = "33")] MaxPredicateCacheSize(u64), } + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] + pub enum FilterPushdownMinBytesPerSecOpt { + #[prost(double, tag = "42")] + FilterPushdownMinBytesPerSec(f64), + } + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] + pub enum FilterCollectingByteRatioThresholdOpt { + #[prost(double, tag = "40")] + FilterCollectingByteRatioThreshold(f64), + } + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] + pub enum FilterConfidenceZOpt { + #[prost(double, tag = "41")] + FilterConfidenceZ(f64), + } } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Precision { diff --git a/datafusion/proto/src/logical_plan/file_formats.rs b/datafusion/proto/src/logical_plan/file_formats.rs index 08f42b0af7290..3cb8058df15d0 100644 --- a/datafusion/proto/src/logical_plan/file_formats.rs +++ b/datafusion/proto/src/logical_plan/file_formats.rs @@ -379,7 +379,7 @@ mod parquet { parquet_options::MetadataSizeHintOpt::MetadataSizeHint(size as u64) }), pushdown_filters: global_options.global.pushdown_filters, - reorder_filters: global_options.global.reorder_filters, + force_filter_selections: global_options.global.force_filter_selections, data_pagesize_limit: global_options.global.data_pagesize_limit as u64, write_batch_size: global_options.global.write_batch_size as u64, @@ -426,6 +426,10 @@ mod parquet { max_predicate_cache_size_opt: global_options.global.max_predicate_cache_size.map(|size| { parquet_options::MaxPredicateCacheSizeOpt::MaxPredicateCacheSize(size as u64) }), + allow_morsel_driven: global_options.global.allow_morsel_driven, + filter_pushdown_min_bytes_per_sec_opt: Some(parquet_options::FilterPushdownMinBytesPerSecOpt::FilterPushdownMinBytesPerSec(global_options.global.filter_pushdown_min_bytes_per_sec)), + filter_collecting_byte_ratio_threshold_opt: Some(parquet_options::FilterCollectingByteRatioThresholdOpt::FilterCollectingByteRatioThreshold(global_options.global.filter_collecting_byte_ratio_threshold)), + filter_confidence_z_opt: Some(parquet_options::FilterConfidenceZOpt::FilterConfidenceZ(global_options.global.filter_confidence_z)), }), column_specific_options: column_specific_options.into_iter().map(|(column_name, options)| { ParquetColumnSpecificOptions { @@ -475,7 +479,7 @@ mod parquet { parquet_options::MetadataSizeHintOpt::MetadataSizeHint(size) => *size as usize, }), pushdown_filters: proto.pushdown_filters, - reorder_filters: proto.reorder_filters, + force_filter_selections: proto.force_filter_selections, data_pagesize_limit: proto.data_pagesize_limit as usize, write_batch_size: proto.write_batch_size as usize, @@ -525,6 +529,16 @@ mod parquet { max_predicate_cache_size: proto.max_predicate_cache_size_opt.as_ref().map(|opt| match opt { parquet_options::MaxPredicateCacheSizeOpt::MaxPredicateCacheSize(size) => *size as usize, }), + allow_morsel_driven: proto.allow_morsel_driven, + filter_pushdown_min_bytes_per_sec: proto.filter_pushdown_min_bytes_per_sec_opt.as_ref().map(|opt| match opt { + parquet_options::FilterPushdownMinBytesPerSecOpt::FilterPushdownMinBytesPerSec(v) => *v, + }).unwrap_or(f64::INFINITY), + filter_collecting_byte_ratio_threshold: proto.filter_collecting_byte_ratio_threshold_opt.as_ref().map(|opt| match opt { + parquet_options::FilterCollectingByteRatioThresholdOpt::FilterCollectingByteRatioThreshold(v) => *v, + }).unwrap_or(0.2), + filter_confidence_z: proto.filter_confidence_z_opt.as_ref().map(|opt| match opt { + parquet_options::FilterConfidenceZOpt::FilterConfidenceZ(v) => *v, + }).unwrap_or(2.0), } } } diff --git a/datafusion/proto/src/physical_plan/mod.rs b/datafusion/proto/src/physical_plan/mod.rs index bfba715b91249..f51ac7ce6a98e 100644 --- a/datafusion/proto/src/physical_plan/mod.rs +++ b/datafusion/proto/src/physical_plan/mod.rs @@ -848,6 +848,12 @@ impl protobuf::PhysicalPlanNode { // Parse table schema with partition columns let table_schema = parse_table_schema_from_proto(base_conf)?; + options.global.filter_pushdown_min_bytes_per_sec = ctx + .session_config() + .options() + .execution + .parquet + .filter_pushdown_min_bytes_per_sec; let mut source = ParquetSource::new(table_schema).with_table_parquet_options(options); diff --git a/datafusion/sqllogictest/test_files/dynamic_filter_pushdown_config.slt b/datafusion/sqllogictest/test_files/dynamic_filter_pushdown_config.slt index cbf9f81e425fa..d4e73e0a77d99 100644 --- a/datafusion/sqllogictest/test_files/dynamic_filter_pushdown_config.slt +++ b/datafusion/sqllogictest/test_files/dynamic_filter_pushdown_config.slt @@ -103,8 +103,7 @@ Plan with Metrics 02)--SortExec: TopK(fetch=3), expr=[v@1 DESC], preserve_partitioning=[true], filter=[v@1 IS NULL OR v@1 > 800], metrics=[output_rows=3, ] 03)----ProjectionExec: expr=[id@0 as id, value@1 as v, value@1 + id@0 as name], metrics=[output_rows=10, ] 04)------FilterExec: value@1 > 3, metrics=[output_rows=10, , selectivity=100% (10/10)] -05)--------RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1, metrics=[output_rows=10, ] -06)----------DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/test_data.parquet]]}, projection=[id, value], file_type=parquet, predicate=value@1 > 3 AND DynamicFilter [ value@1 IS NULL OR value@1 > 800 ], pruning_predicate=value_null_count@1 != row_count@2 AND value_max@0 > 3 AND (value_null_count@1 > 0 OR value_null_count@1 != row_count@2 AND value_max@0 > 800), required_guarantees=[], metrics=[output_rows=10, elapsed_compute=1ns, output_bytes=80.0 B, files_ranges_pruned_statistics=1 total → 1 matched, row_groups_pruned_statistics=1 total → 1 matched -> 1 fully matched, row_groups_pruned_bloom_filter=1 total → 1 matched, page_index_pages_pruned=1 total → 1 matched, limit_pruned_row_groups=0 total → 0 matched, bytes_scanned=210, metadata_load_time=, scan_efficiency_ratio=18% (210/1.15 K)] +05)--------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/test_data.parquet], [], [], []]}, projection=[id, value], file_type=parquet, predicate=value@1 > 3 AND DynamicFilter [ value@1 IS NULL OR value@1 > 800 ], pruning_predicate=value_null_count@1 != row_count@2 AND value_max@0 > 3 AND (value_null_count@1 > 0 OR value_null_count@1 != row_count@2 AND value_max@0 > 800), required_guarantees=[], metrics=[output_rows=10, , files_ranges_pruned_statistics=1 total → 1 matched, row_groups_pruned_statistics=1 total → 1 matched -> 1 fully matched, row_groups_pruned_bloom_filter=1 total → 1 matched, page_index_pages_pruned=1 total → 1 matched, limit_pruned_row_groups=0 total → 0 matched, bytes_scanned=210, metadata_load_time=, scan_efficiency_ratio=] statement ok set datafusion.explain.analyze_level = dev; @@ -158,7 +157,7 @@ physical_plan 01)ProjectionExec: expr=[id@1 as id, data@2 as data, info@0 as info] 02)--HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(id@0, id@0)], projection=[info@1, id@2, data@3] 03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_right.parquet]]}, projection=[id, info], file_type=parquet -04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_left.parquet]]}, projection=[id, data], file_type=parquet, predicate=DynamicFilter [ empty ] +04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_left.parquet]]}, projection=[id, data], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Disable Join dynamic filter pushdown statement ok @@ -404,7 +403,7 @@ physical_plan 01)ProjectionExec: expr=[id@1 as id, data@2 as data, info@0 as info] 02)--HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(id@0, id@0)], projection=[info@1, id@2, data@3] 03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_right.parquet]]}, projection=[id, info], file_type=parquet -04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_left.parquet]]}, projection=[id, data], file_type=parquet, predicate=DynamicFilter [ empty ] +04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_left.parquet]]}, projection=[id, data], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Enable TopK, disable Join statement ok @@ -476,8 +475,7 @@ physical_plan 01)AggregateExec: mode=Final, gby=[], aggr=[max(agg_parquet.score)] 02)--CoalescePartitionsExec 03)----AggregateExec: mode=Partial, gby=[], aggr=[max(agg_parquet.score)] -04)------RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1 -05)--------DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/agg_data.parquet]]}, projection=[score], file_type=parquet, predicate=category@0 = alpha AND DynamicFilter [ empty ], pruning_predicate=category_null_count@2 != row_count@3 AND category_min@0 <= alpha AND alpha <= category_max@1, required_guarantees=[category in (alpha)] +04)------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/agg_data.parquet], [], [], []]}, projection=[score], file_type=parquet, predicate=category@0 = alpha AND DynamicFilter [ empty ], pruning_predicate=category_null_count@2 != row_count@3 AND category_min@0 <= alpha AND alpha <= category_max@1, required_guarantees=[category in (alpha)] # Test 4b: COUNT + MAX — DynamicFilter should NOT appear here in mixed aggregates @@ -495,8 +493,7 @@ physical_plan 02)--AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1)), max(agg_parquet.score)] 03)----CoalescePartitionsExec 04)------AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1)), max(agg_parquet.score)] -05)--------RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1 -06)----------DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/agg_data.parquet]]}, projection=[score], file_type=parquet, predicate=category@0 = alpha, pruning_predicate=category_null_count@2 != row_count@3 AND category_min@0 <= alpha AND alpha <= category_max@1, required_guarantees=[category in (alpha)] +05)--------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/agg_data.parquet], [], [], []]}, projection=[score], file_type=parquet, predicate=category@0 = alpha, pruning_predicate=category_null_count@2 != row_count@3 AND category_min@0 <= alpha AND alpha <= category_max@1, required_guarantees=[category in (alpha)] # Disable aggregate dynamic filters only statement ok @@ -515,8 +512,7 @@ physical_plan 01)AggregateExec: mode=Final, gby=[], aggr=[max(agg_parquet.score)] 02)--CoalescePartitionsExec 03)----AggregateExec: mode=Partial, gby=[], aggr=[max(agg_parquet.score)] -04)------RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1 -05)--------DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/agg_data.parquet]]}, projection=[score], file_type=parquet, predicate=category@0 = alpha, pruning_predicate=category_null_count@2 != row_count@3 AND category_min@0 <= alpha AND alpha <= category_max@1, required_guarantees=[category in (alpha)] +04)------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/agg_data.parquet], [], [], []]}, projection=[score], file_type=parquet, predicate=category@0 = alpha, pruning_predicate=category_null_count@2 != row_count@3 AND category_min@0 <= alpha AND alpha <= category_max@1, required_guarantees=[category in (alpha)] statement ok SET datafusion.optimizer.enable_aggregate_dynamic_filter_pushdown = true; @@ -627,7 +623,7 @@ physical_plan 01)ProjectionExec: expr=[id@1 as id, data@2 as data, info@0 as info] 02)--HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(id@0, id@0)], projection=[info@1, id@2, data@3] 03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_right.parquet]]}, projection=[id, info], file_type=parquet -04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_left.parquet]]}, projection=[id, data], file_type=parquet, predicate=DynamicFilter [ empty ] +04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/dynamic_filter_pushdown_config/join_left.parquet]]}, projection=[id, data], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Test 6: Regression test for issue #20213 - dynamic filter applied to wrong table # when subquery join has same column names on both sides. diff --git a/datafusion/sqllogictest/test_files/explain_tree.slt b/datafusion/sqllogictest/test_files/explain_tree.slt index 3a183a7357430..d297641e919c9 100644 --- a/datafusion/sqllogictest/test_files/explain_tree.slt +++ b/datafusion/sqllogictest/test_files/explain_tree.slt @@ -560,23 +560,14 @@ physical_plan 05)│ string_col != foo │ 06)└─────────────┬─────────────┘ 07)┌─────────────┴─────────────┐ -08)│ RepartitionExec │ +08)│ DataSourceExec │ 09)│ -------------------- │ -10)│ partition_count(in->out): │ -11)│ 1 -> 4 │ +10)│ files: 1 │ +11)│ format: parquet │ 12)│ │ -13)│ partitioning_scheme: │ -14)│ RoundRobinBatch(4) │ -15)└─────────────┬─────────────┘ -16)┌─────────────┴─────────────┐ -17)│ DataSourceExec │ -18)│ -------------------- │ -19)│ files: 1 │ -20)│ format: parquet │ -21)│ │ -22)│ predicate: │ -23)│ string_col != foo │ -24)└───────────────────────────┘ +13)│ predicate: │ +14)│ string_col != foo │ +15)└───────────────────────────┘ # Query with filter on memory query TT diff --git a/datafusion/sqllogictest/test_files/information_schema.slt b/datafusion/sqllogictest/test_files/information_schema.slt index b61ceecb24fc0..34942f8c29908 100644 --- a/datafusion/sqllogictest/test_files/information_schema.slt +++ b/datafusion/sqllogictest/test_files/information_schema.slt @@ -228,6 +228,7 @@ datafusion.execution.max_spill_file_size_bytes 134217728 datafusion.execution.meta_fetch_concurrency 32 datafusion.execution.minimum_parallel_output_files 4 datafusion.execution.objectstore_writer_buffer_size 10485760 +datafusion.execution.parquet.allow_morsel_driven true datafusion.execution.parquet.allow_single_file_parallelism true datafusion.execution.parquet.binary_as_string false datafusion.execution.parquet.bloom_filter_fpp NULL @@ -244,6 +245,9 @@ datafusion.execution.parquet.dictionary_enabled true datafusion.execution.parquet.dictionary_page_size_limit 1048576 datafusion.execution.parquet.enable_page_index true datafusion.execution.parquet.encoding NULL +datafusion.execution.parquet.filter_collecting_byte_ratio_threshold 0.05 +datafusion.execution.parquet.filter_confidence_z 2 +datafusion.execution.parquet.filter_pushdown_min_bytes_per_sec 104857600 datafusion.execution.parquet.force_filter_selections false datafusion.execution.parquet.max_predicate_cache_size NULL datafusion.execution.parquet.max_row_group_size 1048576 @@ -252,7 +256,6 @@ datafusion.execution.parquet.maximum_parallel_row_group_writers 1 datafusion.execution.parquet.metadata_size_hint 524288 datafusion.execution.parquet.pruning true datafusion.execution.parquet.pushdown_filters false -datafusion.execution.parquet.reorder_filters false datafusion.execution.parquet.schema_force_view_types true datafusion.execution.parquet.skip_arrow_metadata false datafusion.execution.parquet.skip_metadata true @@ -366,6 +369,7 @@ datafusion.execution.max_spill_file_size_bytes 134217728 Maximum size in bytes f datafusion.execution.meta_fetch_concurrency 32 Number of files to read in parallel when inferring schema and statistics datafusion.execution.minimum_parallel_output_files 4 Guarantees a minimum level of output files running in parallel. RecordBatches will be distributed in round robin fashion to each parallel writer. Each writer is closed and a new file opened once soft_max_rows_per_output_file is reached. datafusion.execution.objectstore_writer_buffer_size 10485760 Size (bytes) of data buffer DataFusion uses when writing output files. This affects the size of the data chunks that are uploaded to remote object stores (e.g. AWS S3). If very large (>= 100 GiB) output files are being written, it may be necessary to increase this size to avoid errors from the remote end point. +datafusion.execution.parquet.allow_morsel_driven true (reading) If true, the parquet reader will share work between partitions using morsel-driven execution. This can help mitigate data skew. datafusion.execution.parquet.allow_single_file_parallelism true (writing) Controls whether DataFusion will attempt to speed up writing parquet files by serializing them in parallel. Each column in each row group in each output file are serialized in parallel leveraging a maximum possible core count of n_files*n_row_groups*n_columns. datafusion.execution.parquet.binary_as_string false (reading) If true, parquet reader will read columns of `Binary/LargeBinary` with `Utf8`, and `BinaryView` with `Utf8View`. Parquet files generated by some legacy writers do not correctly set the UTF8 flag for strings, causing string columns to be loaded as BLOB instead. datafusion.execution.parquet.bloom_filter_fpp NULL (writing) Sets bloom filter false positive probability. If NULL, uses default parquet writer setting @@ -382,6 +386,9 @@ datafusion.execution.parquet.dictionary_enabled true (writing) Sets if dictionar datafusion.execution.parquet.dictionary_page_size_limit 1048576 (writing) Sets best effort maximum dictionary page size, in bytes datafusion.execution.parquet.enable_page_index true (reading) If true, reads the Parquet data page level metadata (the Page Index), if present, to reduce the I/O and number of rows decoded. datafusion.execution.parquet.encoding NULL (writing) Sets default encoding for any column. Valid values are: plain, plain_dictionary, rle, bit_packed, delta_binary_packed, delta_length_byte_array, delta_byte_array, rle_dictionary, and byte_stream_split. These values are not case sensitive. If NULL, uses default parquet writer setting +datafusion.execution.parquet.filter_collecting_byte_ratio_threshold 0.05 (reading) Byte-ratio threshold for applying filters one at a time (iterative pruning; aka row-level) vs. all at once (post-scan). The ratio is computed as: (extra filter bytes not in projection) / (projected bytes). Filters whose extra columns consume a smaller fraction than this threshold are placed as row filters. Filters whose extra columns consume a larger fraction are placed as post-scan filters. Note: filter columns that are already in the query projection have zero extra cost, so such filters always start as row filters regardless of this threshold. Default: 0.05 meaning filters that require less than 5% additional bytes beyond the projection are placed as row filters. Set to INF to place all filters as row filters (skip byte-ratio check). Set to 0 to place all filters as post-scan filters (no filter passes the ratio check). **Interaction with `pushdown_filters`:** Only takes effect when `pushdown_filters = true`. +datafusion.execution.parquet.filter_confidence_z 2 (reading) Z-score for confidence intervals on filter effectiveness. Controls how much statistical evidence is required before promoting or demoting a filter. Lower values = faster decisions with less confidence. Higher values = more conservative, requiring more data. Default: 2.0 (~95% confidence). **Interaction with `pushdown_filters`:** Only takes effect when `pushdown_filters = true`. +datafusion.execution.parquet.filter_pushdown_min_bytes_per_sec 104857600 (reading) Minimum bytes/sec throughput for adaptive filter pushdown. Filters that achieve at least this throughput (bytes_saved / eval_time) are promoted to row filters. f64::INFINITY = no filters promoted (feature disabled). 0.0 = all filters pushed as row filters (no adaptive logic). Default: 104,857,600 bytes/sec (100 MiB/sec), empirically chosen based on TPC-H, TPC-DS, and ClickBench benchmarks on an m4 MacBook Pro. The optimal value for this setting likely depends on the relative cost of CPU vs. IO in your environment, and to some extent the shape of your query. **Interaction with `pushdown_filters`:** This option only takes effect when `pushdown_filters = true`. When pushdown is disabled, all filters run post-scan and this threshold is ignored. datafusion.execution.parquet.force_filter_selections false (reading) Force the use of RowSelections for filter results, when pushdown_filters is enabled. If false, the reader will automatically choose between a RowSelection and a Bitmap based on the number and pattern of selected rows. datafusion.execution.parquet.max_predicate_cache_size NULL (reading) The maximum predicate cache size, in bytes. When `pushdown_filters` is enabled, sets the maximum memory used to cache the results of predicate evaluation between filter evaluation and output generation. Decreasing this value will reduce memory usage, but may increase IO and CPU usage. None means use the default parquet reader setting. 0 means no caching. datafusion.execution.parquet.max_row_group_size 1048576 (writing) Target maximum number of rows in each row group (defaults to 1M rows). Writing larger row groups requires more memory to write, but can get better compression and be faster to read. @@ -390,7 +397,6 @@ datafusion.execution.parquet.maximum_parallel_row_group_writers 1 (writing) By d datafusion.execution.parquet.metadata_size_hint 524288 (reading) If specified, the parquet reader will try and fetch the last `size_hint` bytes of the parquet file optimistically. If not specified, two reads are required: One read to fetch the 8-byte parquet footer and another to fetch the metadata length encoded in the footer Default setting to 512 KiB, which should be sufficient for most parquet files, it can reduce one I/O operation per parquet file. If the metadata is larger than the hint, two reads will still be performed. datafusion.execution.parquet.pruning true (reading) If true, the parquet reader attempts to skip entire row groups based on the predicate in the query and the metadata (min/max values) stored in the parquet file datafusion.execution.parquet.pushdown_filters false (reading) If true, filter expressions are be applied during the parquet decoding operation to reduce the number of rows decoded. This optimization is sometimes called "late materialization". -datafusion.execution.parquet.reorder_filters false (reading) If true, filter expressions evaluated during the parquet decoding operation will be reordered heuristically to minimize the cost of evaluation. If false, the filters are applied in the same order as written in the query datafusion.execution.parquet.schema_force_view_types true (reading) If true, parquet reader will read columns of `Utf8/Utf8Large` with `Utf8View`, and `Binary/BinaryLarge` with `BinaryView`. datafusion.execution.parquet.skip_arrow_metadata false (writing) Skip encoding the embedded arrow metadata in the KV_meta This is analogous to the `ArrowWriterOptions::with_skip_arrow_metadata`. Refer to datafusion.execution.parquet.skip_metadata true (reading) If true, the parquet reader skip the optional embedded metadata that may be in the file Schema. This setting can help avoid schema conflicts when querying multiple parquet files with schemas containing compatible types but different metadata diff --git a/datafusion/sqllogictest/test_files/limit_pruning.slt b/datafusion/sqllogictest/test_files/limit_pruning.slt index 72672b707d4f5..a3e97ae7fa34c 100644 --- a/datafusion/sqllogictest/test_files/limit_pruning.slt +++ b/datafusion/sqllogictest/test_files/limit_pruning.slt @@ -63,7 +63,9 @@ set datafusion.explain.analyze_level = summary; query TT explain analyze select * from tracking_data where species > 'M' AND s >= 50 limit 3; ---- -Plan with Metrics DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/limit_pruning/data.parquet]]}, projection=[species, s], limit=3, file_type=parquet, predicate=species@0 > M AND s@1 >= 50, pruning_predicate=species_null_count@1 != row_count@2 AND species_max@0 > M AND s_null_count@4 != row_count@2 AND s_max@3 >= 50, required_guarantees=[], metrics=[output_rows=3, elapsed_compute=, output_bytes=, files_ranges_pruned_statistics=1 total → 1 matched, row_groups_pruned_statistics=4 total → 3 matched -> 1 fully matched, row_groups_pruned_bloom_filter=3 total → 3 matched, page_index_pages_pruned=2 total → 2 matched, limit_pruned_row_groups=2 total → 0 matched, bytes_scanned=, metadata_load_time=, scan_efficiency_ratio= (171/2.35 K)] +Plan with Metrics +01)CoalescePartitionsExec: fetch=3, metrics=[output_rows=3, ] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/limit_pruning/data.parquet], [], [], []]}, projection=[species, s], limit=3, file_type=parquet, predicate=species@0 > M AND s@1 >= 50, pruning_predicate=species_null_count@1 != row_count@2 AND species_max@0 > M AND s_null_count@4 != row_count@2 AND s_max@3 >= 50, required_guarantees=[], metrics=[output_rows=3, , files_ranges_pruned_statistics=1 total → 1 matched, row_groups_pruned_statistics=4 total → 3 matched -> 1 fully matched, row_groups_pruned_bloom_filter=1 total → 1 matched, page_index_pages_pruned=2 total → 2 matched, limit_pruned_row_groups=2 total → 0 matched, bytes_scanned=, metadata_load_time=, scan_efficiency_ratio= (171/2.35 K)] # limit_pruned_row_groups=0 total → 0 matched # because of order by, scan needs to preserve sort, so limit pruning is disabled @@ -71,8 +73,9 @@ query TT explain analyze select * from tracking_data where species > 'M' AND s >= 50 order by species limit 3; ---- Plan with Metrics -01)SortExec: TopK(fetch=3), expr=[species@0 ASC NULLS LAST], preserve_partitioning=[false], filter=[species@0 < Nlpine Sheep], metrics=[output_rows=3, elapsed_compute=, output_bytes=] -02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/limit_pruning/data.parquet]]}, projection=[species, s], file_type=parquet, predicate=species@0 > M AND s@1 >= 50 AND DynamicFilter [ species@0 < Nlpine Sheep ], pruning_predicate=species_null_count@1 != row_count@2 AND species_max@0 > M AND s_null_count@4 != row_count@2 AND s_max@3 >= 50 AND species_null_count@1 != row_count@2 AND species_min@5 < Nlpine Sheep, required_guarantees=[], metrics=[output_rows=3, elapsed_compute=, output_bytes=, files_ranges_pruned_statistics=1 total → 1 matched, row_groups_pruned_statistics=4 total → 3 matched -> 1 fully matched, row_groups_pruned_bloom_filter=3 total → 3 matched, page_index_pages_pruned=6 total → 6 matched, limit_pruned_row_groups=0 total → 0 matched, bytes_scanned=, metadata_load_time=, scan_efficiency_ratio= (521/2.35 K)] +01)SortPreservingMergeExec: [species@0 ASC NULLS LAST], fetch=3, metrics=[output_rows=3, ] +02)--SortExec: TopK(fetch=3), expr=[species@0 ASC NULLS LAST], preserve_partitioning=[true], filter=[species@0 < Nlpine Sheep], metrics=[output_rows=3, ] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/limit_pruning/data.parquet], [], [], []]}, projection=[species, s], file_type=parquet, predicate=species@0 > M AND s@1 >= 50 AND DynamicFilter [ species@0 < Nlpine Sheep ], pruning_predicate=species_null_count@1 != row_count@2 AND species_max@0 > M AND s_null_count@4 != row_count@2 AND s_max@3 >= 50 AND species_null_count@1 != row_count@2 AND species_min@5 < Nlpine Sheep, required_guarantees=[], metrics=[output_rows=3, , files_ranges_pruned_statistics=3 total → 3 matched, row_groups_pruned_statistics=4 total → 3 matched -> 1 fully matched, row_groups_pruned_bloom_filter=3 total → 3 matched, page_index_pages_pruned=6 total → 6 matched, limit_pruned_row_groups=0 total → 0 matched, bytes_scanned=, metadata_load_time=, scan_efficiency_ratio= (521/2.35 K)] statement ok drop table tracking_data; diff --git a/datafusion/sqllogictest/test_files/parquet.slt b/datafusion/sqllogictest/test_files/parquet.slt index be713b963b451..61d19880db526 100644 --- a/datafusion/sqllogictest/test_files/parquet.slt +++ b/datafusion/sqllogictest/test_files/parquet.slt @@ -459,8 +459,7 @@ logical_plan 02)--TableScan: binary_as_string_default projection=[binary_col, largebinary_col, binaryview_col], partial_filters=[CAST(binary_as_string_default.binary_col AS Utf8View) LIKE Utf8View("%a%"), CAST(binary_as_string_default.largebinary_col AS Utf8View) LIKE Utf8View("%a%"), CAST(binary_as_string_default.binaryview_col AS Utf8View) LIKE Utf8View("%a%")] physical_plan 01)FilterExec: CAST(binary_col@0 AS Utf8View) LIKE %a% AND CAST(largebinary_col@1 AS Utf8View) LIKE %a% AND CAST(binaryview_col@2 AS Utf8View) LIKE %a% -02)--RepartitionExec: partitioning=RoundRobinBatch(2), input_partitions=1 -03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet/binary_as_string.parquet]]}, projection=[binary_col, largebinary_col, binaryview_col], file_type=parquet, predicate=CAST(binary_col@0 AS Utf8View) LIKE %a% AND CAST(largebinary_col@1 AS Utf8View) LIKE %a% AND CAST(binaryview_col@2 AS Utf8View) LIKE %a% +02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet/binary_as_string.parquet], []]}, projection=[binary_col, largebinary_col, binaryview_col], file_type=parquet, predicate=CAST(binary_col@0 AS Utf8View) LIKE %a% AND CAST(largebinary_col@1 AS Utf8View) LIKE %a% AND CAST(binaryview_col@2 AS Utf8View) LIKE %a% statement ok @@ -506,8 +505,7 @@ logical_plan 02)--TableScan: binary_as_string_option projection=[binary_col, largebinary_col, binaryview_col], partial_filters=[binary_as_string_option.binary_col LIKE Utf8View("%a%"), binary_as_string_option.largebinary_col LIKE Utf8View("%a%"), binary_as_string_option.binaryview_col LIKE Utf8View("%a%")] physical_plan 01)FilterExec: binary_col@0 LIKE %a% AND largebinary_col@1 LIKE %a% AND binaryview_col@2 LIKE %a% -02)--RepartitionExec: partitioning=RoundRobinBatch(2), input_partitions=1 -03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet/binary_as_string.parquet]]}, projection=[binary_col, largebinary_col, binaryview_col], file_type=parquet, predicate=binary_col@0 LIKE %a% AND largebinary_col@1 LIKE %a% AND binaryview_col@2 LIKE %a% +02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet/binary_as_string.parquet], []]}, projection=[binary_col, largebinary_col, binaryview_col], file_type=parquet, predicate=binary_col@0 LIKE %a% AND largebinary_col@1 LIKE %a% AND binaryview_col@2 LIKE %a% statement ok @@ -556,8 +554,7 @@ logical_plan 02)--TableScan: binary_as_string_both projection=[binary_col, largebinary_col, binaryview_col], partial_filters=[binary_as_string_both.binary_col LIKE Utf8View("%a%"), binary_as_string_both.largebinary_col LIKE Utf8View("%a%"), binary_as_string_both.binaryview_col LIKE Utf8View("%a%")] physical_plan 01)FilterExec: binary_col@0 LIKE %a% AND largebinary_col@1 LIKE %a% AND binaryview_col@2 LIKE %a% -02)--RepartitionExec: partitioning=RoundRobinBatch(2), input_partitions=1 -03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet/binary_as_string.parquet]]}, projection=[binary_col, largebinary_col, binaryview_col], file_type=parquet, predicate=binary_col@0 LIKE %a% AND largebinary_col@1 LIKE %a% AND binaryview_col@2 LIKE %a% +02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet/binary_as_string.parquet], []]}, projection=[binary_col, largebinary_col, binaryview_col], file_type=parquet, predicate=binary_col@0 LIKE %a% AND largebinary_col@1 LIKE %a% AND binaryview_col@2 LIKE %a% statement ok @@ -670,8 +667,7 @@ logical_plan 02)--TableScan: foo projection=[column1], partial_filters=[foo.column1 LIKE Utf8View("f%")] physical_plan 01)FilterExec: column1@0 LIKE f% -02)--RepartitionExec: partitioning=RoundRobinBatch(2), input_partitions=1 -03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet/foo.parquet]]}, projection=[column1], file_type=parquet, predicate=column1@0 LIKE f%, pruning_predicate=column1_null_count@2 != row_count@3 AND column1_min@0 <= g AND f <= column1_max@1, required_guarantees=[] +02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet/foo.parquet], []]}, projection=[column1], file_type=parquet, predicate=column1@0 LIKE f%, pruning_predicate=column1_null_count@2 != row_count@3 AND column1_min@0 <= g AND f <= column1_max@1, required_guarantees=[] statement ok drop table foo diff --git a/datafusion/sqllogictest/test_files/parquet_filter_pushdown.slt b/datafusion/sqllogictest/test_files/parquet_filter_pushdown.slt index e2473ee328e51..ab7ae51dec5c7 100644 --- a/datafusion/sqllogictest/test_files/parquet_filter_pushdown.slt +++ b/datafusion/sqllogictest/test_files/parquet_filter_pushdown.slt @@ -96,8 +96,7 @@ physical_plan 01)SortPreservingMergeExec: [a@0 ASC NULLS LAST] 02)--SortExec: expr=[a@0 ASC NULLS LAST], preserve_partitioning=[true] 03)----FilterExec: b@1 > 2, projection=[a@0] -04)------RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2 -05)--------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a, b], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] +04)------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a, b], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] query TT EXPLAIN select a from t_pushdown where b > 2 ORDER BY a; @@ -110,7 +109,7 @@ logical_plan physical_plan 01)SortPreservingMergeExec: [a@0 ASC NULLS LAST] 02)--SortExec: expr=[a@0 ASC NULLS LAST], preserve_partitioning=[true] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] query T select a from t where b = 2 ORDER BY b; @@ -133,8 +132,7 @@ logical_plan physical_plan 01)CoalescePartitionsExec 02)--FilterExec: b@1 = 2, projection=[a@0] -03)----RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2 -04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a, b], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a, b], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] query TT EXPLAIN select a from t_pushdown where b = 2 ORDER BY b; @@ -146,7 +144,7 @@ logical_plan 04)------TableScan: t_pushdown projection=[a, b], partial_filters=[t_pushdown.b = Int32(2)] physical_plan 01)CoalescePartitionsExec -02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] # If we set the setting to `true` it override's the table's setting statement ok @@ -181,7 +179,7 @@ logical_plan physical_plan 01)SortPreservingMergeExec: [a@0 ASC NULLS LAST] 02)--SortExec: expr=[a@0 ASC NULLS LAST], preserve_partitioning=[true] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] query TT EXPLAIN select a from t_pushdown where b > 2 ORDER BY a; @@ -194,7 +192,7 @@ logical_plan physical_plan 01)SortPreservingMergeExec: [a@0 ASC NULLS LAST] 02)--SortExec: expr=[a@0 ASC NULLS LAST], preserve_partitioning=[true] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] query T select a from t where b = 2 ORDER BY b; @@ -216,7 +214,7 @@ logical_plan 04)------TableScan: t projection=[a, b], partial_filters=[t.b = Int32(2)] physical_plan 01)CoalescePartitionsExec -02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] query TT EXPLAIN select a from t_pushdown where b = 2 ORDER BY b; @@ -228,7 +226,7 @@ logical_plan 04)------TableScan: t_pushdown projection=[a, b], partial_filters=[t_pushdown.b = Int32(2)] physical_plan 01)CoalescePartitionsExec -02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] # If we reset the default the table created without pushdown goes back to disabling it statement ok @@ -264,8 +262,7 @@ physical_plan 01)SortPreservingMergeExec: [a@0 ASC NULLS LAST] 02)--SortExec: expr=[a@0 ASC NULLS LAST], preserve_partitioning=[true] 03)----FilterExec: b@1 > 2, projection=[a@0] -04)------RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2 -05)--------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a, b], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] +04)------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a, b], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] query TT EXPLAIN select a from t_pushdown where b > 2 ORDER BY a; @@ -278,7 +275,7 @@ logical_plan physical_plan 01)SortPreservingMergeExec: [a@0 ASC NULLS LAST] 02)--SortExec: expr=[a@0 ASC NULLS LAST], preserve_partitioning=[true] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] query T select a from t where b = 2 ORDER BY b; @@ -301,8 +298,7 @@ logical_plan physical_plan 01)CoalescePartitionsExec 02)--FilterExec: b@1 = 2, projection=[a@0] -03)----RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2 -04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a, b], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a, b], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] query TT EXPLAIN select a from t_pushdown where b = 2 ORDER BY b; @@ -314,7 +310,7 @@ logical_plan 04)------TableScan: t_pushdown projection=[a, b], partial_filters=[t_pushdown.b = Int32(2)] physical_plan 01)CoalescePartitionsExec -02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] # When filter pushdown *is* enabled, ParquetExec can filter exactly, # not just metadata, so we expect to see no FilterExec @@ -339,8 +335,7 @@ physical_plan 01)SortPreservingMergeExec: [a@0 ASC NULLS LAST] 02)--SortExec: expr=[a@0 ASC NULLS LAST], preserve_partitioning=[true] 03)----FilterExec: b@1 > 2, projection=[a@0] -04)------RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2 -05)--------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a, b], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] +04)------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a, b], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] query T select a from t_pushdown where b = 2 ORDER BY b; @@ -357,7 +352,7 @@ logical_plan 04)------TableScan: t_pushdown projection=[a, b], partial_filters=[t_pushdown.b = Int32(2)] physical_plan 01)CoalescePartitionsExec -02)--DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 = 2, pruning_predicate=b_null_count@2 != row_count@3 AND b_min@0 <= 2 AND 2 <= b_max@1, required_guarantees=[b in (2)] # also test querying on columns that are not in all the files query T @@ -377,7 +372,7 @@ logical_plan physical_plan 01)SortPreservingMergeExec: [a@0 ASC NULLS LAST] 02)--SortExec: expr=[a@0 ASC NULLS LAST], preserve_partitioning=[true] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[a], file_type=parquet, predicate=b@1 > 2 AND a@0 IS NOT NULL, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2 AND a_null_count@3 != row_count@2, required_guarantees=[] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[a], file_type=parquet, predicate=b@1 > 2 AND a@0 IS NOT NULL, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2 AND a_null_count@3 != row_count@2, required_guarantees=[] query I @@ -396,7 +391,7 @@ logical_plan physical_plan 01)SortPreservingMergeExec: [b@0 ASC NULLS LAST] 02)--SortExec: expr=[b@0 ASC NULLS LAST], preserve_partitioning=[true] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet]]}, projection=[b], file_type=parquet, predicate=a@0 = bar, pruning_predicate=a_null_count@2 != row_count@3 AND a_min@0 <= bar AND bar <= a_max@1, required_guarantees=[a in (bar)] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/2.parquet], [], []]}, projection=[b], file_type=parquet, predicate=a@0 = bar, pruning_predicate=a_null_count@2 != row_count@3 AND a_min@0 <= bar AND bar <= a_max@1, required_guarantees=[a in (bar)] # should not push down volatile predicates such as RANDOM @@ -466,7 +461,7 @@ EXPLAIN select * from t_pushdown where part != val logical_plan 01)Filter: t_pushdown.val != t_pushdown.part 02)--TableScan: t_pushdown projection=[val, part], partial_filters=[t_pushdown.val != t_pushdown.part] -physical_plan DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=b/file.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=c/file.parquet]]}, projection=[val, part], file_type=parquet, predicate=val@0 != part@1 +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=b/file.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=c/file.parquet], []]}, projection=[val, part], file_type=parquet, predicate=val@0 != part@1 # If we reference only a partition column it gets evaluated during the listing phase query TT @@ -482,7 +477,7 @@ EXPLAIN select * from t_pushdown where val != 'c'; logical_plan 01)Filter: t_pushdown.val != Utf8View("c") 02)--TableScan: t_pushdown projection=[val, part], partial_filters=[t_pushdown.val != Utf8View("c")] -physical_plan DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=b/file.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=c/file.parquet]]}, projection=[val, part], file_type=parquet, predicate=val@0 != c, pruning_predicate=val_null_count@2 != row_count@3 AND (val_min@0 != c OR c != val_max@1), required_guarantees=[val not in (c)] +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=b/file.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=c/file.parquet], []]}, projection=[val, part], file_type=parquet, predicate=val@0 != c, pruning_predicate=val_null_count@2 != row_count@3 AND (val_min@0 != c OR c != val_max@1), required_guarantees=[val not in (c)] # If we have a mix of filters: # - The partition filters get evaluated during planning @@ -494,7 +489,7 @@ EXPLAIN select * from t_pushdown where val != 'd' AND val != 'c' AND part = 'a' logical_plan 01)Filter: t_pushdown.val != Utf8View("d") AND t_pushdown.val != Utf8View("c") AND t_pushdown.val != t_pushdown.part 02)--TableScan: t_pushdown projection=[val, part], full_filters=[t_pushdown.part = Utf8View("a")], partial_filters=[t_pushdown.val != Utf8View("d"), t_pushdown.val != Utf8View("c"), t_pushdown.val != t_pushdown.part] -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet]]}, projection=[val, part], file_type=parquet, predicate=val@0 != d AND val@0 != c AND val@0 != part@1, pruning_predicate=val_null_count@2 != row_count@3 AND (val_min@0 != d OR d != val_max@1) AND val_null_count@2 != row_count@3 AND (val_min@0 != c OR c != val_max@1), required_guarantees=[val not in (c, d)] +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet], [], [], []]}, projection=[val, part], file_type=parquet, predicate=val@0 != d AND val@0 != c AND val@0 != part@1, pruning_predicate=val_null_count@2 != row_count@3 AND (val_min@0 != d OR d != val_max@1) AND val_null_count@2 != row_count@3 AND (val_min@0 != c OR c != val_max@1), required_guarantees=[val not in (c, d)] # The order of filters should not matter query TT @@ -503,7 +498,7 @@ EXPLAIN select val, part from t_pushdown where part = 'a' AND part = val; logical_plan 01)Filter: t_pushdown.val = t_pushdown.part 02)--TableScan: t_pushdown projection=[val, part], full_filters=[t_pushdown.part = Utf8View("a")], partial_filters=[t_pushdown.val = t_pushdown.part] -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet]]}, projection=[val, part], file_type=parquet, predicate=val@0 = part@1 +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet], [], [], []]}, projection=[val, part], file_type=parquet, predicate=val@0 = part@1 query TT select val, part from t_pushdown where part = 'a' AND part = val; @@ -516,7 +511,7 @@ EXPLAIN select val, part from t_pushdown where part = val AND part = 'a'; logical_plan 01)Filter: t_pushdown.val = t_pushdown.part 02)--TableScan: t_pushdown projection=[val, part], full_filters=[t_pushdown.part = Utf8View("a")], partial_filters=[t_pushdown.val = t_pushdown.part] -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet]]}, projection=[val, part], file_type=parquet, predicate=val@0 = part@1 +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_part_test/part=a/file.parquet], [], [], []]}, projection=[val, part], file_type=parquet, predicate=val@0 = part@1 query TT select val, part from t_pushdown where part = val AND part = 'a'; @@ -602,8 +597,9 @@ logical_plan 02)--Filter: array_has(array_test.tags, Utf8("rust")) 03)----TableScan: array_test projection=[id, tags], partial_filters=[array_has(array_test.tags, Utf8("rust"))] physical_plan -01)SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[false] -02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet]]}, projection=[id, tags], file_type=parquet, predicate=array_has(tags@1, rust) +01)SortPreservingMergeExec: [id@0 ASC NULLS LAST] +02)--SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[true] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet], [], [], []]}, projection=[id, tags], file_type=parquet, predicate=array_has(tags@1, rust) # Test array_has_all predicate pushdown query I? @@ -619,8 +615,9 @@ logical_plan 02)--Filter: array_has_all(array_test.tags, List([rust, performance])) 03)----TableScan: array_test projection=[id, tags], partial_filters=[array_has_all(array_test.tags, List([rust, performance]))] physical_plan -01)SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[false] -02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet]]}, projection=[id, tags], file_type=parquet, predicate=array_has_all(tags@1, [rust, performance]) +01)SortPreservingMergeExec: [id@0 ASC NULLS LAST] +02)--SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[true] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet], [], [], []]}, projection=[id, tags], file_type=parquet, predicate=array_has_all(tags@1, [rust, performance]) # Test array_has_any predicate pushdown query I? @@ -636,8 +633,9 @@ logical_plan 02)--Filter: array_has_any(array_test.tags, List([python, go])) 03)----TableScan: array_test projection=[id, tags], partial_filters=[array_has_any(array_test.tags, List([python, go]))] physical_plan -01)SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[false] -02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet]]}, projection=[id, tags], file_type=parquet, predicate=array_has_any(tags@1, [python, go]) +01)SortPreservingMergeExec: [id@0 ASC NULLS LAST] +02)--SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[true] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet], [], [], []]}, projection=[id, tags], file_type=parquet, predicate=array_has_any(tags@1, [python, go]) # Test complex predicate with OR query I? @@ -655,8 +653,9 @@ logical_plan 02)--Filter: array_has_all(array_test.tags, List([rust])) OR array_has_any(array_test.tags, List([python, go])) 03)----TableScan: array_test projection=[id, tags], partial_filters=[array_has_all(array_test.tags, List([rust])) OR array_has_any(array_test.tags, List([python, go]))] physical_plan -01)SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[false] -02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet]]}, projection=[id, tags], file_type=parquet, predicate=array_has_all(tags@1, [rust]) OR array_has_any(tags@1, [python, go]) +01)SortPreservingMergeExec: [id@0 ASC NULLS LAST] +02)--SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[true] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet], [], [], []]}, projection=[id, tags], file_type=parquet, predicate=array_has_all(tags@1, [rust]) OR array_has_any(tags@1, [python, go]) # Test array function with other predicates query I? @@ -672,8 +671,9 @@ logical_plan 02)--Filter: array_test.id > Int64(1) AND array_has(array_test.tags, Utf8("rust")) 03)----TableScan: array_test projection=[id, tags], partial_filters=[array_test.id > Int64(1), array_has(array_test.tags, Utf8("rust"))] physical_plan -01)SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[false] -02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet]]}, projection=[id, tags], file_type=parquet, predicate=id@0 > 1 AND array_has(tags@1, rust), pruning_predicate=id_null_count@1 != row_count@2 AND id_max@0 > 1, required_guarantees=[] +01)SortPreservingMergeExec: [id@0 ASC NULLS LAST] +02)--SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[true] +03)----DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/array_data/data.parquet], [], [], []]}, projection=[id, tags], file_type=parquet, predicate=id@0 > 1 AND array_has(tags@1, rust), pruning_predicate=id_null_count@1 != row_count@2 AND id_max@0 > 1, required_guarantees=[] ### # Test filter pushdown through UNION with mixed support @@ -729,7 +729,7 @@ physical_plan 01)UnionExec 02)--FilterExec: b@0 > 2 03)----DataSourceExec: partitions=1, partition_sizes=[1] -04)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet]]}, projection=[b], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] +04)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_filter_pushdown/parquet_table/1.parquet], [], [], []]}, projection=[b], file_type=parquet, predicate=b@1 > 2, pruning_predicate=b_null_count@1 != row_count@2 AND b_max@0 > 2, required_guarantees=[] # Clean up union test tables statement ok diff --git a/datafusion/sqllogictest/test_files/parquet_statistics.slt b/datafusion/sqllogictest/test_files/parquet_statistics.slt index 8c77fb96ba75c..bc2555aa688d0 100644 --- a/datafusion/sqllogictest/test_files/parquet_statistics.slt +++ b/datafusion/sqllogictest/test_files/parquet_statistics.slt @@ -60,8 +60,7 @@ EXPLAIN SELECT * FROM test_table WHERE column1 = 1; ---- physical_plan 01)FilterExec: column1@0 = 1, statistics=[Rows=Inexact(2), Bytes=Inexact(10), [(Col[0]: Min=Exact(Int64(1)) Max=Exact(Int64(1)) Null=Inexact(0) ScanBytes=Inexact(40))]] -02)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2, statistics=[Rows=Inexact(5), Bytes=Inexact(40), [(Col[0]: Min=Inexact(Int64(1)) Max=Inexact(Int64(4)) Null=Inexact(0) ScanBytes=Inexact(40))]] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/1.parquet]]}, projection=[column1], file_type=parquet, predicate=column1@0 = 1, pruning_predicate=column1_null_count@2 != row_count@3 AND column1_min@0 <= 1 AND 1 <= column1_max@1, required_guarantees=[column1 in (1)], statistics=[Rows=Inexact(5), Bytes=Inexact(40), [(Col[0]: Min=Inexact(Int64(1)) Max=Inexact(Int64(4)) Null=Inexact(0) ScanBytes=Inexact(40))]] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/1.parquet], [], []]}, projection=[column1], file_type=parquet, predicate=column1@0 = 1, pruning_predicate=column1_null_count@2 != row_count@3 AND column1_min@0 <= 1 AND 1 <= column1_max@1, required_guarantees=[column1 in (1)], statistics=[Rows=Inexact(5), Bytes=Inexact(40), [(Col[0]: Min=Inexact(Int64(1)) Max=Inexact(Int64(4)) Null=Inexact(0) ScanBytes=Inexact(40))]] # cleanup statement ok @@ -85,8 +84,7 @@ EXPLAIN SELECT * FROM test_table WHERE column1 = 1; ---- physical_plan 01)FilterExec: column1@0 = 1, statistics=[Rows=Inexact(2), Bytes=Inexact(10), [(Col[0]: Min=Exact(Int64(1)) Max=Exact(Int64(1)) Null=Inexact(0) ScanBytes=Inexact(40))]] -02)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2, statistics=[Rows=Inexact(5), Bytes=Inexact(40), [(Col[0]: Min=Inexact(Int64(1)) Max=Inexact(Int64(4)) Null=Inexact(0) ScanBytes=Inexact(40))]] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/1.parquet]]}, projection=[column1], file_type=parquet, predicate=column1@0 = 1, pruning_predicate=column1_null_count@2 != row_count@3 AND column1_min@0 <= 1 AND 1 <= column1_max@1, required_guarantees=[column1 in (1)], statistics=[Rows=Inexact(5), Bytes=Inexact(40), [(Col[0]: Min=Inexact(Int64(1)) Max=Inexact(Int64(4)) Null=Inexact(0) ScanBytes=Inexact(40))]] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/1.parquet], [], []]}, projection=[column1], file_type=parquet, predicate=column1@0 = 1, pruning_predicate=column1_null_count@2 != row_count@3 AND column1_min@0 <= 1 AND 1 <= column1_max@1, required_guarantees=[column1 in (1)], statistics=[Rows=Inexact(5), Bytes=Inexact(40), [(Col[0]: Min=Inexact(Int64(1)) Max=Inexact(Int64(4)) Null=Inexact(0) ScanBytes=Inexact(40))]] # cleanup statement ok @@ -111,8 +109,7 @@ EXPLAIN SELECT * FROM test_table WHERE column1 = 1; ---- physical_plan 01)FilterExec: column1@0 = 1, statistics=[Rows=Absent, Bytes=Absent, [(Col[0]: Min=Exact(Int64(1)) Max=Exact(Int64(1)))]] -02)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=2, statistics=[Rows=Absent, Bytes=Absent, [(Col[0]:)]] -03)----DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/1.parquet]]}, projection=[column1], file_type=parquet, predicate=column1@0 = 1, pruning_predicate=column1_null_count@2 != row_count@3 AND column1_min@0 <= 1 AND 1 <= column1_max@1, required_guarantees=[column1 in (1)], statistics=[Rows=Absent, Bytes=Absent, [(Col[0]:)]] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/parquet_statistics/test_table/1.parquet], [], []]}, projection=[column1], file_type=parquet, predicate=column1@0 = 1, pruning_predicate=column1_null_count@2 != row_count@3 AND column1_min@0 <= 1 AND 1 <= column1_max@1, required_guarantees=[column1 in (1)], statistics=[Rows=Absent, Bytes=Absent, [(Col[0]:)]] # cleanup statement ok diff --git a/datafusion/sqllogictest/test_files/preserve_file_partitioning.slt b/datafusion/sqllogictest/test_files/preserve_file_partitioning.slt index 297094fab16e7..7fa458c1e6980 100644 --- a/datafusion/sqllogictest/test_files/preserve_file_partitioning.slt +++ b/datafusion/sqllogictest/test_files/preserve_file_partitioning.slt @@ -368,9 +368,8 @@ physical_plan 08)--------------HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_dkey@0, f_dkey@1)], projection=[env@1, service@2, value@3, f_dkey@4] 09)----------------CoalescePartitionsExec 10)------------------FilterExec: service@2 = log -11)--------------------RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=1 -12)----------------------DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/dimension/data.parquet]]}, projection=[d_dkey, env, service], file_type=parquet, predicate=service@2 = log, pruning_predicate=service_null_count@2 != row_count@3 AND service_min@0 <= log AND log <= service_max@1, required_guarantees=[service in (log)] -13)----------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=C/data.parquet]]}, projection=[value, f_dkey], output_ordering=[f_dkey@1 ASC NULLS LAST], file_type=parquet, predicate=DynamicFilter [ empty ] +11)--------------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/dimension/data.parquet], [], []]}, projection=[d_dkey, env, service], file_type=parquet, predicate=service@2 = log, pruning_predicate=service_null_count@2 != row_count@3 AND service_min@0 <= log AND log <= service_max@1, required_guarantees=[service in (log)] +12)----------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=C/data.parquet]]}, projection=[value, f_dkey], output_ordering=[f_dkey@1 ASC NULLS LAST], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify results without optimization query TTTIR rowsort @@ -420,9 +419,8 @@ physical_plan 05)--------HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_dkey@0, f_dkey@1)], projection=[env@1, service@2, value@3, f_dkey@4] 06)----------CoalescePartitionsExec 07)------------FilterExec: service@2 = log -08)--------------RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=1 -09)----------------DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/dimension/data.parquet]]}, projection=[d_dkey, env, service], file_type=parquet, predicate=service@2 = log, pruning_predicate=service_null_count@2 != row_count@3 AND service_min@0 <= log AND log <= service_max@1, required_guarantees=[service in (log)] -10)----------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=C/data.parquet]]}, projection=[value, f_dkey], output_ordering=[f_dkey@1 ASC NULLS LAST], file_type=parquet, predicate=DynamicFilter [ empty ] +08)--------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/dimension/data.parquet], [], []]}, projection=[d_dkey, env, service], file_type=parquet, predicate=service@2 = log, pruning_predicate=service_null_count@2 != row_count@3 AND service_min@0 <= log AND log <= service_max@1, required_guarantees=[service in (log)] +09)----------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=C/data.parquet]]}, projection=[value, f_dkey], output_ordering=[f_dkey@1 ASC NULLS LAST], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) query TTTIR rowsort SELECT f.f_dkey, MAX(d.env), MAX(d.service), count(*), sum(f.value) @@ -648,7 +646,7 @@ physical_plan 06)----------RepartitionExec: partitioning=Hash([d_dkey@1], 3), input_partitions=3 07)------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/dimension_partitioned/d_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/dimension_partitioned/d_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/dimension_partitioned/d_dkey=C/data.parquet]]}, projection=[env, d_dkey], file_type=parquet 08)----------RepartitionExec: partitioning=Hash([f_dkey@1], 3), input_partitions=3 -09)------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=C/data.parquet]]}, projection=[value, f_dkey], file_type=parquet, predicate=DynamicFilter [ empty ] +09)------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/preserve_file_partitioning/fact/f_dkey=C/data.parquet]]}, projection=[value, f_dkey], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) query TTR rowsort SELECT f.f_dkey, d.env, sum(f.value) diff --git a/datafusion/sqllogictest/test_files/projection.slt b/datafusion/sqllogictest/test_files/projection.slt index e18114bc51ca8..a2f434118cacd 100644 --- a/datafusion/sqllogictest/test_files/projection.slt +++ b/datafusion/sqllogictest/test_files/projection.slt @@ -276,5 +276,4 @@ logical_plan 03)----TableScan: t1 projection=[a], partial_filters=[t1.a > Int64(1)] physical_plan 01)FilterExec: a@0 > 1, projection=[] -02)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1 -03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection/17513.parquet]]}, projection=[a], file_type=parquet, predicate=a@0 > 1, pruning_predicate=a_null_count@1 != row_count@2 AND a_max@0 > 1, required_guarantees=[] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection/17513.parquet], [], [], []]}, projection=[a], file_type=parquet, predicate=a@0 > 1, pruning_predicate=a_null_count@1 != row_count@2 AND a_max@0 > 1, required_guarantees=[] diff --git a/datafusion/sqllogictest/test_files/projection_pushdown.slt b/datafusion/sqllogictest/test_files/projection_pushdown.slt index dbb77b33c21b7..cd05d5b816861 100644 --- a/datafusion/sqllogictest/test_files/projection_pushdown.slt +++ b/datafusion/sqllogictest/test_files/projection_pushdown.slt @@ -762,8 +762,7 @@ physical_plan 02)--SortExec: expr=[id@0 ASC NULLS LAST], preserve_partitioning=[true] 03)----ProjectionExec: expr=[id@1 as id, __datafusion_extracted_1@0 as multi_struct.s[value]] 04)------FilterExec: id@1 > 2 -05)--------RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=3 -06)----------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part1.parquet, WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part2.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part3.parquet, WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part4.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part5.parquet]]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, id], file_type=parquet, predicate=id@0 > 2, pruning_predicate=id_null_count@1 != row_count@2 AND id_max@0 > 2, required_guarantees=[] +05)--------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part1.parquet, WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part5.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part2.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part3.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/multi/part4.parquet]]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, id], file_type=parquet, predicate=id@0 > 2, pruning_predicate=id_null_count@1 != row_count@2 AND id_max@0 > 2, required_guarantees=[] # Verify correctness query II @@ -1457,7 +1456,7 @@ physical_plan 01)HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(id@0, id@0)] 02)--FilterExec: __datafusion_extracted_1@0 > 150, projection=[id@1] 03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet]]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, id], file_type=parquet -04)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[id], file_type=parquet, predicate=DynamicFilter [ empty ] +04)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[id], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify correctness - id matches and value > 150 query II @@ -1497,7 +1496,7 @@ physical_plan 02)--FilterExec: __datafusion_extracted_1@0 > 100, projection=[id@1] 03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet]]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, id], file_type=parquet 04)--FilterExec: __datafusion_extracted_2@0 > 3, projection=[id@1] -05)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[get_field(s@1, level) as __datafusion_extracted_2, id], file_type=parquet, predicate=DynamicFilter [ empty ] +05)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[get_field(s@1, level) as __datafusion_extracted_2, id], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify correctness - id matches, value > 100, and level > 3 # Matching ids where value > 100: 2(200), 3(150), 4(300), 5(250) @@ -1533,7 +1532,7 @@ physical_plan 01)ProjectionExec: expr=[id@1 as id, __datafusion_extracted_1@0 as simple_struct.s[label], __datafusion_extracted_2@2 as join_right.s[role]] 02)--HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(id@1, id@1)], projection=[__datafusion_extracted_1@0, id@1, __datafusion_extracted_2@2] 03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet]]}, projection=[get_field(s@1, label) as __datafusion_extracted_1, id], file_type=parquet -04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[get_field(s@1, role) as __datafusion_extracted_2, id], file_type=parquet, predicate=DynamicFilter [ empty ] +04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[get_field(s@1, role) as __datafusion_extracted_2, id], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify correctness query ITT @@ -1565,7 +1564,7 @@ logical_plan physical_plan 01)HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(id@0, id@0)] 02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet]]}, projection=[id], file_type=parquet -03)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[id], file_type=parquet, predicate=DynamicFilter [ empty ] +03)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[id], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify correctness query II @@ -1639,8 +1638,7 @@ logical_plan physical_plan 01)ProjectionExec: expr=[__datafusion_extracted_1@0 as simple_struct.s[value]] 02)--FilterExec: id@1 > 2, projection=[__datafusion_extracted_1@0] -03)----RepartitionExec: partitioning=RoundRobinBatch(32), input_partitions=1 -04)------DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet]]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, id], file_type=parquet, predicate=id@0 > 2, pruning_predicate=id_null_count@1 != row_count@2 AND id_max@0 > 2, required_guarantees=[] +03)----DataSourceExec: file_groups={32 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet], [], [], [], [], ...]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, id], file_type=parquet, predicate=id@0 > 2, pruning_predicate=id_null_count@1 != row_count@2 AND id_max@0 > 2, required_guarantees=[] ##################### # Section 14: SubqueryAlias tests @@ -1896,7 +1894,7 @@ physical_plan 01)ProjectionExec: expr=[__datafusion_extracted_3@1 as s.s[value], __datafusion_extracted_4@0 as j.s[role]] 02)--HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(id@2, id@2)], filter=__datafusion_extracted_1@1 > __datafusion_extracted_2@0, projection=[__datafusion_extracted_4@1, __datafusion_extracted_3@4] 03)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[get_field(s@1, level) as __datafusion_extracted_2, get_field(s@1, role) as __datafusion_extracted_4, id], file_type=parquet -04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet]]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, get_field(s@1, value) as __datafusion_extracted_3, id], file_type=parquet, predicate=DynamicFilter [ empty ] +04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet]]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, get_field(s@1, value) as __datafusion_extracted_3, id], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify correctness - only admin roles match (ids 1 and 4) query II @@ -1932,7 +1930,7 @@ logical_plan physical_plan 01)HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(id@1, id@1)], filter=__datafusion_extracted_1@0 > __datafusion_extracted_2@1, projection=[id@1, id@3] 02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/simple.parquet]]}, projection=[get_field(s@1, value) as __datafusion_extracted_1, id], file_type=parquet -03)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[get_field(s@1, level) as __datafusion_extracted_2, id], file_type=parquet, predicate=DynamicFilter [ empty ] +03)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/projection_pushdown/join_right.parquet]]}, projection=[get_field(s@1, level) as __datafusion_extracted_2, id], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify correctness - all rows match since value >> level for all ids # simple_struct: (1,100), (2,200), (3,150), (4,300), (5,250) diff --git a/datafusion/sqllogictest/test_files/push_down_filter_parquet.slt b/datafusion/sqllogictest/test_files/push_down_filter_parquet.slt index e1c83c8c330d8..8e4ea6fdc6c26 100644 --- a/datafusion/sqllogictest/test_files/push_down_filter_parquet.slt +++ b/datafusion/sqllogictest/test_files/push_down_filter_parquet.slt @@ -77,7 +77,7 @@ explain select * from test_filter_with_limit where value = 2 limit 1; ---- physical_plan 01)CoalescePartitionsExec: fetch=1 -02)--DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/test_filter_with_limit/part-0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/test_filter_with_limit/part-1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/test_filter_with_limit/part-2.parquet]]}, projection=[part_key, value], limit=1, file_type=parquet, predicate=value@1 = 2, pruning_predicate=value_null_count@2 != row_count@3 AND value_min@0 <= 2 AND 2 <= value_max@1, required_guarantees=[value in (2)] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/test_filter_with_limit/part-0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/test_filter_with_limit/part-1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/test_filter_with_limit/part-2.parquet], []]}, projection=[part_key, value], limit=1, file_type=parquet, predicate=value@1 = 2, pruning_predicate=value_null_count@2 != row_count@3 AND value_min@0 <= 2 AND 2 <= value_max@1, required_guarantees=[value in (2)] query II select * from test_filter_with_limit where value = 2 limit 1; @@ -114,43 +114,43 @@ LOCATION 'test_files/scratch/push_down_filter_parquet/t.parquet'; query TT explain select a from t where a = '100'; ---- -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet]]}, projection=[a], file_type=parquet, predicate=a@0 = 100, pruning_predicate=a_null_count@2 != row_count@3 AND a_min@0 <= 100 AND 100 <= a_max@1, required_guarantees=[a in (100)] +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet], [], [], []]}, projection=[a], file_type=parquet, predicate=a@0 = 100, pruning_predicate=a_null_count@2 != row_count@3 AND a_min@0 <= 100 AND 100 <= a_max@1, required_guarantees=[a in (100)] # The predicate should not have a column cast when the value is a valid i32 query TT explain select a from t where a != '100'; ---- -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet]]}, projection=[a], file_type=parquet, predicate=a@0 != 100, pruning_predicate=a_null_count@2 != row_count@3 AND (a_min@0 != 100 OR 100 != a_max@1), required_guarantees=[a not in (100)] +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet], [], [], []]}, projection=[a], file_type=parquet, predicate=a@0 != 100, pruning_predicate=a_null_count@2 != row_count@3 AND (a_min@0 != 100 OR 100 != a_max@1), required_guarantees=[a not in (100)] # The predicate should still have the column cast when the value is a NOT valid i32 query TT explain select a from t where a = '99999999999'; ---- -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet]]}, projection=[a], file_type=parquet, predicate=CAST(a@0 AS Utf8) = 99999999999 +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet], [], [], []]}, projection=[a], file_type=parquet, predicate=CAST(a@0 AS Utf8) = 99999999999 # The predicate should still have the column cast when the value is a NOT valid i32 query TT explain select a from t where a = '99.99'; ---- -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet]]}, projection=[a], file_type=parquet, predicate=CAST(a@0 AS Utf8) = 99.99 +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet], [], [], []]}, projection=[a], file_type=parquet, predicate=CAST(a@0 AS Utf8) = 99.99 # The predicate should still have the column cast when the value is a NOT valid i32 query TT explain select a from t where a = ''; ---- -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet]]}, projection=[a], file_type=parquet, predicate=CAST(a@0 AS Utf8) = +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet], [], [], []]}, projection=[a], file_type=parquet, predicate=CAST(a@0 AS Utf8) = # The predicate should not have a column cast when the operator is = or != and the literal can be round-trip casted without losing information. query TT explain select a from t where cast(a as string) = '100'; ---- -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet]]}, projection=[a], file_type=parquet, predicate=a@0 = 100, pruning_predicate=a_null_count@2 != row_count@3 AND a_min@0 <= 100 AND 100 <= a_max@1, required_guarantees=[a in (100)] +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet], [], [], []]}, projection=[a], file_type=parquet, predicate=a@0 = 100, pruning_predicate=a_null_count@2 != row_count@3 AND a_min@0 <= 100 AND 100 <= a_max@1, required_guarantees=[a in (100)] # The predicate should still have the column cast when the literal alters its string representation after round-trip casting (leading zero lost). query TT explain select a from t where CAST(a AS string) = '0123'; ---- -physical_plan DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet]]}, projection=[a], file_type=parquet, predicate=CAST(a@0 AS Utf8View) = 0123 +physical_plan DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/t.parquet], [], [], []]}, projection=[a], file_type=parquet, predicate=CAST(a@0 AS Utf8View) = 0123 # Test dynamic filter pushdown with swapped join inputs (issue #17196) @@ -175,8 +175,7 @@ explain select * from small_table join large_table on small_table.k = large_tabl physical_plan 01)HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(k@0, k@0)] 02)--DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/small_table.parquet]]}, projection=[k], file_type=parquet -03)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1 -04)----DataSourceExec: file_groups={1 group: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/large_table.parquet]]}, projection=[k, v], file_type=parquet, predicate=v@1 >= 50 AND DynamicFilter [ empty ], pruning_predicate=v_null_count@1 != row_count@2 AND v_max@0 >= 50, required_guarantees=[] +03)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/push_down_filter_parquet/large_table.parquet], [], [], []]}, projection=[k, v], file_type=parquet, predicate=v@1 >= 50 AND Optional(DynamicFilter [ empty ]), pruning_predicate=v_null_count@1 != row_count@2 AND v_max@0 >= 50, required_guarantees=[] statement ok drop table small_table; diff --git a/datafusion/sqllogictest/test_files/push_down_filter_regression.slt b/datafusion/sqllogictest/test_files/push_down_filter_regression.slt index ca4a30fa96c35..3f9828a5d6eca 100644 --- a/datafusion/sqllogictest/test_files/push_down_filter_regression.slt +++ b/datafusion/sqllogictest/test_files/push_down_filter_regression.slt @@ -151,7 +151,7 @@ physical_plan 01)AggregateExec: mode=Final, gby=[], aggr=[max(agg_dyn_test.id)] 02)--CoalescePartitionsExec 03)----AggregateExec: mode=Partial, gby=[], aggr=[max(agg_dyn_test.id)] -04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-01/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-02/j5fUeSDQo22oPyPU.parquet], [WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-03/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-04/j5fUeSDQo22oPyPU.parquet]]}, projection=[id], file_type=parquet, predicate=id@0 > 1 AND DynamicFilter [ empty ], pruning_predicate=id_null_count@1 != row_count@2 AND id_max@0 > 1, required_guarantees=[] +04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-01/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-03/j5fUeSDQo22oPyPU.parquet], [WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-02/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-04/j5fUeSDQo22oPyPU.parquet]]}, projection=[id], file_type=parquet, predicate=id@0 > 1 AND DynamicFilter [ empty ], pruning_predicate=id_null_count@1 != row_count@2 AND id_max@0 > 1, required_guarantees=[] query I select max(id) from agg_dyn_test where id > 1; @@ -166,7 +166,7 @@ physical_plan 01)AggregateExec: mode=Final, gby=[], aggr=[max(agg_dyn_test.id)] 02)--CoalescePartitionsExec 03)----AggregateExec: mode=Partial, gby=[], aggr=[max(agg_dyn_test.id)] -04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-01/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-02/j5fUeSDQo22oPyPU.parquet], [WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-03/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-04/j5fUeSDQo22oPyPU.parquet]]}, projection=[id], file_type=parquet, predicate=CAST(id@0 AS Int64) + 1 > 1 AND DynamicFilter [ empty ] +04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-01/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-03/j5fUeSDQo22oPyPU.parquet], [WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-02/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-04/j5fUeSDQo22oPyPU.parquet]]}, projection=[id], file_type=parquet, predicate=CAST(id@0 AS Int64) + 1 > 1 AND DynamicFilter [ empty ] # Expect dynamic filter available inside data source query TT @@ -176,7 +176,7 @@ physical_plan 01)AggregateExec: mode=Final, gby=[], aggr=[max(agg_dyn_test.id), min(agg_dyn_test.id)] 02)--CoalescePartitionsExec 03)----AggregateExec: mode=Partial, gby=[], aggr=[max(agg_dyn_test.id), min(agg_dyn_test.id)] -04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-01/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-02/j5fUeSDQo22oPyPU.parquet], [WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-03/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-04/j5fUeSDQo22oPyPU.parquet]]}, projection=[id], file_type=parquet, predicate=id@0 < 10 AND DynamicFilter [ empty ], pruning_predicate=id_null_count@1 != row_count@2 AND id_min@0 < 10, required_guarantees=[] +04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-01/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-03/j5fUeSDQo22oPyPU.parquet], [WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-02/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-04/j5fUeSDQo22oPyPU.parquet]]}, projection=[id], file_type=parquet, predicate=id@0 < 10 AND DynamicFilter [ empty ], pruning_predicate=id_null_count@1 != row_count@2 AND id_min@0 < 10, required_guarantees=[] # Dynamic filter should not be available for grouping sets query TT @@ -188,7 +188,7 @@ physical_plan 02)--AggregateExec: mode=FinalPartitioned, gby=[id@0 as id, __grouping_id@1 as __grouping_id], aggr=[max(agg_dyn_test.id)] 03)----RepartitionExec: partitioning=Hash([id@0, __grouping_id@1], 2), input_partitions=2 04)------AggregateExec: mode=Partial, gby=[(NULL as id), (id@0 as id)], aggr=[max(agg_dyn_test.id)] -05)--------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-01/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-02/j5fUeSDQo22oPyPU.parquet], [WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-03/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-04/j5fUeSDQo22oPyPU.parquet]]}, projection=[id], file_type=parquet, predicate=id@0 < 10, pruning_predicate=id_null_count@1 != row_count@2 AND id_min@0 < 10, required_guarantees=[] +05)--------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-01/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-03/j5fUeSDQo22oPyPU.parquet], [WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-02/j5fUeSDQo22oPyPU.parquet, WORKSPACE_ROOT/datafusion/core/tests/data/test_statistics_per_partition/date=2025-03-04/j5fUeSDQo22oPyPU.parquet]]}, projection=[id], file_type=parquet, predicate=id@0 < 10, pruning_predicate=id_null_count@1 != row_count@2 AND id_min@0 < 10, required_guarantees=[] statement ok drop table agg_dyn_test; diff --git a/datafusion/sqllogictest/test_files/repartition_scan.slt b/datafusion/sqllogictest/test_files/repartition_scan.slt index c9c2f91257081..c47fc20d9ce80 100644 --- a/datafusion/sqllogictest/test_files/repartition_scan.slt +++ b/datafusion/sqllogictest/test_files/repartition_scan.slt @@ -55,7 +55,7 @@ select * from parquet_table; 4 5 -## Expect to see the scan read the file as "4" groups with even sizes (offsets) +## Expect to see the scan with whole files distributed across groups (morsel-driven handles load balancing) query TT EXPLAIN SELECT column1 FROM parquet_table WHERE column1 <> 42; ---- @@ -64,13 +64,13 @@ logical_plan 02)--TableScan: parquet_table projection=[column1], partial_filters=[parquet_table.column1 != Int32(42)] physical_plan 01)FilterExec: column1@0 != 42 -02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:0..135], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:135..270], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:270..405], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:405..537]]}, projection=[column1], file_type=parquet, predicate=column1@0 != 42, pruning_predicate=column1_null_count@2 != row_count@3 AND (column1_min@0 != 42 OR 42 != column1_max@1), required_guarantees=[column1 not in (42)] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet], [], [], []]}, projection=[column1], file_type=parquet, predicate=column1@0 != 42, pruning_predicate=column1_null_count@2 != row_count@3 AND (column1_min@0 != 42 OR 42 != column1_max@1), required_guarantees=[column1 not in (42)] # disable round robin repartitioning statement ok set datafusion.optimizer.enable_round_robin_repartition = false; -## Expect to see the scan read the file as "4" groups with even sizes (offsets) again +## Expect to see the same plan (morsel-driven doesn't depend on round robin) query TT EXPLAIN SELECT column1 FROM parquet_table WHERE column1 <> 42; ---- @@ -79,7 +79,7 @@ logical_plan 02)--TableScan: parquet_table projection=[column1], partial_filters=[parquet_table.column1 != Int32(42)] physical_plan 01)FilterExec: column1@0 != 42 -02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:0..135], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:135..270], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:270..405], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:405..537]]}, projection=[column1], file_type=parquet, predicate=column1@0 != 42, pruning_predicate=column1_null_count@2 != row_count@3 AND (column1_min@0 != 42 OR 42 != column1_max@1), required_guarantees=[column1 not in (42)] +02)--DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet], [], [], []]}, projection=[column1], file_type=parquet, predicate=column1@0 != 42, pruning_predicate=column1_null_count@2 != row_count@3 AND (column1_min@0 != 42 OR 42 != column1_max@1), required_guarantees=[column1 not in (42)] # enable round robin repartitioning again statement ok @@ -90,8 +90,7 @@ statement ok COPY (VALUES (100), (200)) TO 'test_files/scratch/repartition_scan/parquet_table/1.parquet' STORED AS PARQUET; -## Still expect to see the scan read the file as "4" groups with even sizes. One group should read -## parts of both files. +## Expect to see whole files distributed round-robin across groups query TT EXPLAIN SELECT column1 FROM parquet_table WHERE column1 <> 42 ORDER BY column1; ---- @@ -103,7 +102,7 @@ physical_plan 01)SortPreservingMergeExec: [column1@0 ASC NULLS LAST] 02)--SortExec: expr=[column1@0 ASC NULLS LAST], preserve_partitioning=[true] 03)----FilterExec: column1@0 != 42 -04)------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/1.parquet:0..266], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/1.parquet:266..526, WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:0..6], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:6..272], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet:272..537]]}, projection=[column1], file_type=parquet, predicate=column1@0 != 42, pruning_predicate=column1_null_count@2 != row_count@3 AND (column1_min@0 != 42 OR 42 != column1_max@1), required_guarantees=[column1 not in (42)] +04)------DataSourceExec: file_groups={4 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/1.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_scan/parquet_table/2.parquet], [], []]}, projection=[column1], file_type=parquet, predicate=column1@0 != 42, pruning_predicate=column1_null_count@2 != row_count@3 AND (column1_min@0 != 42 OR 42 != column1_max@1), required_guarantees=[column1 not in (42)] ## Read the files as though they are ordered diff --git a/datafusion/sqllogictest/test_files/repartition_subset_satisfaction.slt b/datafusion/sqllogictest/test_files/repartition_subset_satisfaction.slt index e2c9fa4237939..682a7681a228c 100644 --- a/datafusion/sqllogictest/test_files/repartition_subset_satisfaction.slt +++ b/datafusion/sqllogictest/test_files/repartition_subset_satisfaction.slt @@ -383,7 +383,7 @@ physical_plan 14)--------------------------CoalescePartitionsExec 15)----------------------------FilterExec: service@1 = log, projection=[env@0, d_dkey@2] 16)------------------------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/dimension/d_dkey=A/data.parquet, WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/dimension/d_dkey=D/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/dimension/d_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/dimension/d_dkey=C/data.parquet]]}, projection=[env, service, d_dkey], file_type=parquet, predicate=service@1 = log, pruning_predicate=service_null_count@2 != row_count@3 AND service_min@0 <= log AND log <= service_max@1, required_guarantees=[service in (log)] -17)--------------------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=C/data.parquet]]}, projection=[timestamp, value, f_dkey], output_ordering=[f_dkey@2 ASC NULLS LAST, timestamp@0 ASC NULLS LAST], file_type=parquet, predicate=DynamicFilter [ empty ] +17)--------------------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=C/data.parquet]]}, projection=[timestamp, value, f_dkey], output_ordering=[f_dkey@2 ASC NULLS LAST, timestamp@0 ASC NULLS LAST], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify results without subset satisfaction query TPR rowsort @@ -479,7 +479,7 @@ physical_plan 11)--------------------CoalescePartitionsExec 12)----------------------FilterExec: service@1 = log, projection=[env@0, d_dkey@2] 13)------------------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/dimension/d_dkey=A/data.parquet, WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/dimension/d_dkey=D/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/dimension/d_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/dimension/d_dkey=C/data.parquet]]}, projection=[env, service, d_dkey], file_type=parquet, predicate=service@1 = log, pruning_predicate=service_null_count@2 != row_count@3 AND service_min@0 <= log AND log <= service_max@1, required_guarantees=[service in (log)] -14)--------------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=C/data.parquet]]}, projection=[timestamp, value, f_dkey], output_ordering=[f_dkey@2 ASC NULLS LAST, timestamp@0 ASC NULLS LAST], file_type=parquet, predicate=DynamicFilter [ empty ] +14)--------------------DataSourceExec: file_groups={3 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=A/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=B/data.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch/repartition_subset_satisfaction/fact/f_dkey=C/data.parquet]]}, projection=[timestamp, value, f_dkey], output_ordering=[f_dkey@2 ASC NULLS LAST, timestamp@0 ASC NULLS LAST], file_type=parquet, predicate=Optional(DynamicFilter [ empty ]) # Verify results match with subset satisfaction query TPR rowsort diff --git a/diff.txt b/diff.txt new file mode 100644 index 0000000000000..b9be9a5da8ccb --- /dev/null +++ b/diff.txt @@ -0,0 +1,42 @@ +diff --git a/datafusion/physical-optimizer/src/projection_pushdown.rs b/datafusion/physical-optimizer/src/projection_pushdown.rs +index ce85e4c20..2489dfc10 100644 +--- a/datafusion/physical-optimizer/src/projection_pushdown.rs ++++ b/datafusion/physical-optimizer/src/projection_pushdown.rs +@@ -35,7 +35,7 @@ use datafusion_common::{JoinSide, JoinType, Result}; + use datafusion_expr::ExpressionPlacement; + use datafusion_physical_expr::expressions::Column; + use datafusion_physical_expr::projection::ProjectionExpr; +-use datafusion_physical_expr_common::physical_expr::PhysicalExpr; ++use datafusion_physical_expr_common::physical_expr::{PhysicalExpr, is_volatile}; + use datafusion_physical_plan::ExecutionPlan; + use datafusion_physical_plan::joins::NestedLoopJoinExec; + use datafusion_physical_plan::joins::utils::{ColumnIndex, JoinFilter}; +@@ -624,8 +624,7 @@ impl<'a> JoinFilterRewriter<'a> { + // Recurse if there is a dependency to both sides or if the entire expression is volatile. + let depends_on_other_side = + self.depends_on_join_side(&expr, self.join_side.negate())?; +- let is_volatile = is_volatile_expression_tree(expr.as_ref()); +- if depends_on_other_side || is_volatile { ++ if depends_on_other_side || is_volatile(&expr) { + return expr.map_children(|expr| self.rewrite(expr)); + } + +@@ -706,18 +705,6 @@ impl<'a> JoinFilterRewriter<'a> { + } + } + +-fn is_volatile_expression_tree(expr: &dyn PhysicalExpr) -> bool { +- if expr.is_volatile_node() { +- return true; +- } +- +- expr.children() +- .iter() +- .map(|expr| is_volatile_expression_tree(expr.as_ref())) +- .reduce(|lhs, rhs| lhs || rhs) +- .unwrap_or(false) +-} +- + #[cfg(test)] + mod test { + use super::*; diff --git a/docs/source/user-guide/configs.md b/docs/source/user-guide/configs.md index e48f0a7c92276..e2501b5687d6f 100644 --- a/docs/source/user-guide/configs.md +++ b/docs/source/user-guide/configs.md @@ -85,13 +85,16 @@ The following configuration settings are available: | datafusion.execution.parquet.skip_metadata | true | (reading) If true, the parquet reader skip the optional embedded metadata that may be in the file Schema. This setting can help avoid schema conflicts when querying multiple parquet files with schemas containing compatible types but different metadata | | datafusion.execution.parquet.metadata_size_hint | 524288 | (reading) If specified, the parquet reader will try and fetch the last `size_hint` bytes of the parquet file optimistically. If not specified, two reads are required: One read to fetch the 8-byte parquet footer and another to fetch the metadata length encoded in the footer Default setting to 512 KiB, which should be sufficient for most parquet files, it can reduce one I/O operation per parquet file. If the metadata is larger than the hint, two reads will still be performed. | | datafusion.execution.parquet.pushdown_filters | false | (reading) If true, filter expressions are be applied during the parquet decoding operation to reduce the number of rows decoded. This optimization is sometimes called "late materialization". | -| datafusion.execution.parquet.reorder_filters | false | (reading) If true, filter expressions evaluated during the parquet decoding operation will be reordered heuristically to minimize the cost of evaluation. If false, the filters are applied in the same order as written in the query | | datafusion.execution.parquet.force_filter_selections | false | (reading) Force the use of RowSelections for filter results, when pushdown_filters is enabled. If false, the reader will automatically choose between a RowSelection and a Bitmap based on the number and pattern of selected rows. | | datafusion.execution.parquet.schema_force_view_types | true | (reading) If true, parquet reader will read columns of `Utf8/Utf8Large` with `Utf8View`, and `Binary/BinaryLarge` with `BinaryView`. | | datafusion.execution.parquet.binary_as_string | false | (reading) If true, parquet reader will read columns of `Binary/LargeBinary` with `Utf8`, and `BinaryView` with `Utf8View`. Parquet files generated by some legacy writers do not correctly set the UTF8 flag for strings, causing string columns to be loaded as BLOB instead. | | datafusion.execution.parquet.coerce_int96 | NULL | (reading) If true, parquet reader will read columns of physical type int96 as originating from a different resolution than nanosecond. This is useful for reading data from systems like Spark which stores microsecond resolution timestamps in an int96 allowing it to write values with a larger date range than 64-bit timestamps with nanosecond resolution. | | datafusion.execution.parquet.bloom_filter_on_read | true | (reading) Use any available bloom filters when reading parquet files | +| datafusion.execution.parquet.allow_morsel_driven | true | (reading) If true, the parquet reader will share work between partitions using morsel-driven execution. This can help mitigate data skew. | | datafusion.execution.parquet.max_predicate_cache_size | NULL | (reading) The maximum predicate cache size, in bytes. When `pushdown_filters` is enabled, sets the maximum memory used to cache the results of predicate evaluation between filter evaluation and output generation. Decreasing this value will reduce memory usage, but may increase IO and CPU usage. None means use the default parquet reader setting. 0 means no caching. | +| datafusion.execution.parquet.filter_pushdown_min_bytes_per_sec | 104857600 | (reading) Minimum bytes/sec throughput for adaptive filter pushdown. Filters that achieve at least this throughput (bytes_saved / eval_time) are promoted to row filters. f64::INFINITY = no filters promoted (feature disabled). 0.0 = all filters pushed as row filters (no adaptive logic). Default: 104,857,600 bytes/sec (100 MiB/sec), empirically chosen based on TPC-H, TPC-DS, and ClickBench benchmarks on an m4 MacBook Pro. The optimal value for this setting likely depends on the relative cost of CPU vs. IO in your environment, and to some extent the shape of your query. **Interaction with `pushdown_filters`:** This option only takes effect when `pushdown_filters = true`. When pushdown is disabled, all filters run post-scan and this threshold is ignored. | +| datafusion.execution.parquet.filter_collecting_byte_ratio_threshold | 0.05 | (reading) Byte-ratio threshold for applying filters one at a time (iterative pruning; aka row-level) vs. all at once (post-scan). The ratio is computed as: (extra filter bytes not in projection) / (projected bytes). Filters whose extra columns consume a smaller fraction than this threshold are placed as row filters. Filters whose extra columns consume a larger fraction are placed as post-scan filters. Note: filter columns that are already in the query projection have zero extra cost, so such filters always start as row filters regardless of this threshold. Default: 0.05 meaning filters that require less than 5% additional bytes beyond the projection are placed as row filters. Set to INF to place all filters as row filters (skip byte-ratio check). Set to 0 to place all filters as post-scan filters (no filter passes the ratio check). **Interaction with `pushdown_filters`:** Only takes effect when `pushdown_filters = true`. | +| datafusion.execution.parquet.filter_confidence_z | 2 | (reading) Z-score for confidence intervals on filter effectiveness. Controls how much statistical evidence is required before promoting or demoting a filter. Lower values = faster decisions with less confidence. Higher values = more conservative, requiring more data. Default: 2.0 (~95% confidence). **Interaction with `pushdown_filters`:** Only takes effect when `pushdown_filters = true`. | | datafusion.execution.parquet.data_pagesize_limit | 1048576 | (writing) Sets best effort maximum size of data page in bytes | | datafusion.execution.parquet.write_batch_size | 1024 | (writing) Sets write_batch_size in rows | | datafusion.execution.parquet.writer_version | 1.0 | (writing) Sets parquet writer version valid values are "1.0" and "2.0" | diff --git a/docs/source/user-guide/sql/format_options.md b/docs/source/user-guide/sql/format_options.md index 338508031413c..3f4b8bc3f184b 100644 --- a/docs/source/user-guide/sql/format_options.md +++ b/docs/source/user-guide/sql/format_options.md @@ -147,7 +147,6 @@ The following options are available when reading or writing Parquet files. If an | SKIP_METADATA | No | If true, skips optional embedded metadata in the file schema. | `'skip_metadata'` | true | | METADATA_SIZE_HINT | No | Sets the size hint (in bytes) for fetching Parquet file metadata. | `'metadata_size_hint'` | None | | PUSHDOWN_FILTERS | No | If true, enables filter pushdown during Parquet decoding. | `'pushdown_filters'` | false | -| REORDER_FILTERS | No | If true, enables heuristic reordering of filters during Parquet decoding. | `'reorder_filters'` | false | | SCHEMA_FORCE_VIEW_TYPES | No | If true, reads Utf8/Binary columns as view types. | `'schema_force_view_types'` | true | | BINARY_AS_STRING | No | If true, reads Binary columns as strings. | `'binary_as_string'` | false | | DATA_PAGESIZE_LIMIT | No | Sets best effort maximum size of data page in bytes. | `'data_pagesize_limit'` | 1048576 | diff --git a/fixes.md b/fixes.md new file mode 100644 index 0000000000000..c0f8c6e4522c8 --- /dev/null +++ b/fixes.md @@ -0,0 +1,41 @@ +# Review Status: `extract_leaf_expressions.rs` (PR #20117) + +Checked against current state of `get-field-pushdown-try-3` branch (3rd pass). + +## Fixed (15 of 17) + +| # | Issue | How it was resolved | +|---|-------|---------------------| +| 2 | `try_push_into_inputs` was monolithic (~177 lines) | Split into `push_extraction_pairs` (~53 lines), `route_to_inputs` (~46 lines), `try_push_into_inputs` (~93 lines). SubqueryAlias/Union remapping extracted into shared `remap_pairs_and_columns` helper (line 298). | +| 3 | Complex 4-way match `(pushed, needs_recovery)` | Refactored into 2-step pattern: `match pushed` for `Some`/`None` (lines 867-887) then `if needs_recovery` (lines 889-898). Reads linearly now. | +| 4 | `find_owning_input` used `position()` — wrong input for ambiguous unqualified columns | Replaced with explicit loop returning `None` on ambiguity (lines 217-222). Dedicated unit test `test_find_owning_input_ambiguous_unqualified_column` (line 2344) verifies unqualified columns matching both sides return `None`, while qualified columns resolve correctly. | +| 5 | `build_recovery_projection` positional mapping had undocumented invariant | Comment (lines 408-410) now documents that `with_new_exprs` on all supported node types preserves column order. Added `debug_assert!` (lines 411-414) as safety net. | +| 6 | `(None, false)` case comment was misleading | 4-way match eliminated (see #3); the `None` path is now self-documenting. | +| 8 | `transformed.data.with_new_exprs(...)` was uncommented | Comment at lines 196-197: "Rebuild the plan keeping its rewritten expressions but replacing inputs with the new extraction projections." | +| 9 | Comment inconsistency: `__extracted_N` vs `__datafusion_extracted` | All comments now consistently use the full prefix `__datafusion_extracted` / `__datafusion_extracted_N`. | +| 10 | `pairs.len() + columns_needed.len() == proj.expr.len()` could overcount | Completely reworked. A dedicated `proj_exprs_captured` counter (line 762) tracks only Case A (`__datafusion_extracted` aliases) and Case B (standalone `Expr::Column`) expressions. The merge guard is now `proj_exprs_captured == proj.expr.len()` (line 939). Additionally, `standalone_columns` (line 765) detects when `columns_needed` has entries from extracted alias internals that aren't standalone projection columns, triggering `needs_recovery` (line 850). Regression test at line 2929. | +| 11 | No Join tests | 9 Join tests: equijoin keys, non-equi filter, both-sides extraction, no-extraction, filter-above-join, projection-above-join, qualified right side, cross-input expression, left join. | +| 12 | No test for `(None, true)` recovery fallback | `test_projection_with_leaf_expr_above_aggregate` (line 1954) explicitly tests this: mixed projection with leaf expressions above Aggregate, which blocks pushdown — fires the in-place extraction + recovery path. | +| 13 | No test for cross-input expressions | `test_extract_from_join_cross_input_expression` (line 2390) tests a filter where each side of `=` references a different Join input. Confirms each expression is extracted and routed independently. | +| 14 | `test_extract_from_projection` optimized plan had spurious self-alias | Optimized plan now shows `Projection: leaf_udf(test.user, Utf8("name"))` without alias (line 1340). | +| 15 | `extract_from_plan` cloned all inputs before checking if transformation occurred | Inputs cloned only after `transformed.transformed` check (lines 168-179). Wrap directly in `Arc`, consume with `into_iter()` (line 183), recover without clone via `Arc::try_unwrap` (line 190). | +| 15b | Double-clone when extraction succeeds | Fixed. `Arc` wrapping happens once (line 178); `into_iter()` consumes the vec (line 183); `Arc::try_unwrap` (line 190) avoids a second clone when the refcount is 1. | + +## Partially Fixed (1 of 17) + +| # | Issue | What changed | What remains | +|---|-------|-------------|--------------| +| 1 | Two separate projection-building paths (`build_extraction_projection` vs `build_extraction_projection_impl`) | `build_extraction_projection` documents delegation (lines 490-492). `build_extraction_projection_impl` doc says "shared by both passes" (line 517). | `_impl` is called directly from `split_and_push_projection` (line 879) and `try_push_into_inputs` (line 1114), bypassing the wrapper. This is intentional — those callers already have pairs/columns extracted separately — but the two entry points with similar names can confuse new readers. | + +## Still Present (Low Severity, 1 of 17) + +| # | Issue | Severity | Details | +|---|-------|----------|---------| +| 7 | `routing_extract` only tracks `Expr::Column` variants in `columns_needed` | Low | Only `Expr::Column` nodes trigger pass-through tracking (line 271). The `ExpressionPlacement::Column` match arm (line 265) has an `if let Expr::Column` guard. In DataFusion today, `ExpressionPlacement::Column` is only returned by `Expr::Column`, so this is correct. If a future expression variant returned `Column` placement without being `Expr::Column`, it would be silently skipped. | + +## By-Design / Not Issues + +| # | Original issue | Why it's fine | +|---|---------------|---------------| +| 16 | `schema_columns` allocates both qualified and unqualified forms | By design — enables `has_all_column_refs` to work with both qualified and unqualified column references. The ambiguity this creates in multi-input routing is now handled by `find_owning_input` returning `None` on ambiguity (#4 fix). | +| 17 | Recursive `try_push_input` calls with no explicit depth limit | By design — recursion at lines 959 and 1134 is bounded by plan tree depth and guard conditions (`is_pure_extraction_projection`, `None` on barriers). Each call pushes the projection exactly one level deeper, and the plan tree is finite. | diff --git a/improvements.md b/improvements.md new file mode 100644 index 0000000000000..ae951472d0d21 --- /dev/null +++ b/improvements.md @@ -0,0 +1,32 @@ +# Adaptive Filter Pushdown Improvements + +## 1. Projection-aware byte ratio (selectivity.rs, opener.rs, config.rs) + +The byte ratio that decides whether a new filter starts as row-level or post-scan now only counts **extra** columns not already in the query projection. Previously, a filter on a column already being read (e.g. `WHERE URL LIKE ...` with `SELECT *`) was penalized for its byte cost even though those bytes are read regardless. Now such filters correctly get zero extra cost and start as row filters, enabling late materialization savings. + +**Files:** `selectivity.rs` (partition_filters), `opener.rs` (passes `projection_columns`), `config.rs` (doc update) + +## 2. Fix sort order for row filters (selectivity.rs) + +Filters without effectiveness stats were sorted **largest first** (most expensive). Changed to **cheapest first** — cheap filters should run first to prune rows before expensive filters evaluate, reducing total work. + +## 3. Fix demote_or_drop cycle for non-optional filters (selectivity.rs) + +Non-optional PostScan filters with poor stats were repeatedly passed to `demote_or_drop`, which reset their stats each time, creating an infinite cycle where they never accumulated meaningful data. Now only optional filters (e.g. dynamic join filters) can be dropped; mandatory PostScan filters keep their stats and stay as post-scan. + +## 4. Fix TrackerConfig::new() default (selectivity.rs) + +`TrackerConfig::new()` had `byte_ratio_threshold: 0.2` but `config.rs` declared the default as `0.05`. Aligned the constructor to `0.05`. + +## Benchmark Results + +**ClickBench Partitioned** (pushdown_filters=true, target_partitions=1): +- Q23 (URL LIKE): 1.84x faster (1,285ms vs 2,349ms) — projection-aware fix +- Q22 (URL NOT LIKE): correctly kept post-scan, avoiding regression +- Total runtime roughly unchanged vs baseline + +**TPC-DS SF1**: 6.3% faster overall (47.4s vs 50.6s), with large wins on: +- Q82: 4.75x faster +- Q37: 3.76x faster +- Q9: 2.72x faster +- Q24: 2.61x faster diff --git a/more-sort.md b/more-sort.md new file mode 100644 index 0000000000000..6dec4a2251b64 --- /dev/null +++ b/more-sort.md @@ -0,0 +1,176 @@ +# Handle complex projections in ordering validation + +## Problem + +`get_projected_output_ordering()` uses `ordered_column_indices_from_projection()` to build a +mapping from projected column indices → table-schema indices, needed so `MinMaxStatistics` can +look up file-level statistics. But `ordered_column_indices_from_projection` is **all-or-nothing**: +if *any* expression in the projection isn't a simple `Column`, it returns `None` for the entire +projection — even if the sort columns themselves are simple column refs. + +With projection pushdown (`try_merge`), complex expressions in the file source's `ProjectionExprs` +are common. For example: + +```sql +SELECT a + 1 AS x, b, c FROM t ORDER BY b +``` + +col1min,col1max +a,a -> RecordBatch 2 row +b,b -> RecordBatch 8092 rows +b,b -> RecordBatch 8092 rows + +a,b -> RowGroup 1 +b,b -> RowGroup 2 + + + +After pushdown the projection is `[BinaryExpr(a+1), col(b), col(c)]`. The ordering on `b` +(projected index 1) maps cleanly to a simple `Column`, but `ordered_column_indices_from_projection` +fails on index 0 and returns `None`. With multi-file groups, this causes valid orderings to be +unnecessarily dropped. + +## Key insight + +`MinMaxStatistics::new_from_files` only indexes the projection at sort-column positions +(`statistics.rs:138-140`): + +```rust +let i = projection + .map(|p| p[c.index()]) // only accesses sort-column positions + .unwrap_or_else(|| c.index()); +``` + +We don't need a full projection mapping — just the entries at sort-column positions. + +## Files to modify + +- `datafusion/datasource/src/file_scan_config.rs` + +## Changes + +### 1. Replace `ordered_column_indices_from_projection` with per-ordering resolution + +Replace the current all-or-nothing function: + +```rust +fn ordered_column_indices_from_projection( + projection: &ProjectionExprs, +) -> Option> { + projection + .expr_iter() + .map(|e| { + let index = e.as_any().downcast_ref::()?.index(); + Some(index) + }) + .collect::>>() +} +``` + +With a function that resolves projection indices only for the columns referenced by a +specific ordering: + +```rust +/// For each sort column in `ordering`, look up its position in `projection` and +/// try to resolve it to a table-schema column index. Returns `Some(indices)` if +/// every sort column maps to a simple `Column` in the projection, `None` otherwise. +fn resolve_sort_column_projection( + ordering: &LexOrdering, + projection: &ProjectionExprs, +) -> Option> { + ordering + .iter() + .map(|sort_expr| { + let col = sort_expr.expr.as_any().downcast_ref::()?; + let proj_expr = projection.expr_at(col.index())?; + proj_expr.as_any().downcast_ref::().map(|c| c.index()) + }) + .collect() +} +``` + +Note: this requires a way to get a projection expression by index. `ProjectionExprs` already +exposes `expr_iter()` — check if there's an indexed accessor, or use `expr_iter().nth(idx)`. + +### 2. Refactor `get_projected_output_ordering` to validate per-ordering + +Instead of pre-computing a single projection mapping and branching on `Some(Some(_))` / +`None` / `Some(None)`, move the resolution inside `validate_orderings` (or into a new +variant) so each ordering is independently resolved: + +```rust +fn get_projected_output_ordering( + base_config: &FileScanConfig, + projected_schema: &SchemaRef, +) -> Vec { + let projected_orderings = + project_orderings(&base_config.output_ordering, projected_schema); + + let projection = base_config.file_source.projection(); + + projected_orderings + .into_iter() + .filter(|ordering| { + match projection.as_ref() { + None => { + // No projection — validate directly with statistics + is_ordering_valid_for_file_groups( + &base_config.file_groups, ordering, projected_schema, None, + ) + } + Some(proj) => { + match resolve_sort_column_projection(ordering, proj) { + Some(indices) => { + // All sort columns resolved — validate with statistics + is_ordering_valid_for_file_groups( + &base_config.file_groups, + ordering, + projected_schema, + Some(&indices), + ) + } + None => { + // Some sort column is a complex expression — can't + // look up statistics. Fall back to single-file check. + base_config.file_groups.iter().all(|g| g.len() <= 1) + } + } + } + } + }) + .collect() +} +``` + +This collapses the three match arms into a clean per-ordering pipeline. The `Some(None)` case +(complex sort column) now only applies to orderings that actually reference non-Column +expressions — other orderings in the same scan that reference simple columns still get +validated with statistics. + +### 3. Remove `ordered_column_indices_from_projection` + +It's no longer called anywhere after step 2. Delete it. + +### 4. Check `ProjectionExprs` accessor + +`resolve_sort_column_projection` needs to access a projection expression by index. +Check whether `ProjectionExprs` has an indexed accessor (e.g. `expr_at(idx)`, +`Index` impl, or similar). If not, `expr_iter().nth(idx)` works but is O(n) per call. +If needed, add a small `pub fn expr_at(&self, idx: usize) -> Option<&dyn PhysicalExpr>` +method to `ProjectionExprs` in `datafusion/physical-expr/src/projection.rs`. + +## Verification + +1. Existing tests must still pass: + ``` + cargo test -p datafusion-datasource + ``` + +2. The SLT sorted-statistics tests: + ``` + cargo test -p datafusion-sqllogictest --test sqllogictests -- parquet_sorted_statistics + ``` + +3. Consider adding a test case with a mixed projection (some expressions, some columns) + and multi-file groups, verifying the ordering on a simple column is retained while + an ordering on a computed expression is dropped. diff --git a/out.csv b/out.csv new file mode 100644 index 0000000000000..84e0e6418b42d --- /dev/null +++ b/out.csv @@ -0,0 +1,6 @@ +id,simple_struct.s[value] + Int64(1) +1,101 +2,201 +3,151 +4,301 +5,251 diff --git a/out.txt b/out.txt new file mode 100644 index 0000000000000..8e707209d662e --- /dev/null +++ b/out.txt @@ -0,0 +1,7 @@ +DataFusion CLI v52.1.0 +0 row(s) fetched. +Elapsed 0.000 seconds. + +0 row(s) fetched. +Elapsed 0.034 seconds. + diff --git a/output.txt b/output.txt new file mode 100644 index 0000000000000..ee9a606966aca --- /dev/null +++ b/output.txt @@ -0,0 +1,9148 @@ + Compiling datafusion-expr v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/expr) + Compiling datafusion-execution v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/execution) + Compiling datafusion-physical-expr v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/physical-expr) + Compiling datafusion-functions v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/functions) + Compiling datafusion-functions-aggregate v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/functions-aggregate) + Compiling datafusion-functions-window v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/functions-window) + Compiling datafusion-optimizer v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/optimizer) + Compiling datafusion-physical-plan v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/physical-plan) + Compiling datafusion-physical-expr-adapter v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/physical-expr-adapter) + Compiling datafusion-functions-nested v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/functions-nested) + Compiling datafusion-sql v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/sql) + Compiling datafusion-session v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/session) + Compiling datafusion-datasource v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/datasource) + Compiling datafusion-pruning v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/pruning) + Compiling datafusion-catalog v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/catalog) + Compiling datafusion-datasource-arrow v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/datasource-arrow) + Compiling datafusion-datasource-json v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/datasource-json) + Compiling datafusion-datasource-csv v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/datasource-csv) + Compiling datafusion-datasource-avro v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/datasource-avro) + Compiling datafusion-datasource-parquet v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/datasource-parquet) + Compiling datafusion-catalog-listing v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/catalog-listing) + Compiling datafusion-functions-table v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/functions-table) + Compiling datafusion-physical-optimizer v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/physical-optimizer) + Compiling datafusion v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/core) + Compiling datafusion-proto v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/proto) + Compiling datafusion-examples v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion-examples) + Compiling datafusion-substrait v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/substrait) + Compiling datafusion-benchmarks v52.1.0 (/Users/adrian/GitHub/datafusion/benchmarks) + Compiling datafusion-cli v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion-cli) + Compiling datafusion-spark v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/spark) + Compiling datafusion-wasmtest v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/wasmtest) + Compiling datafusion-ffi v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/ffi) + Compiling datafusion-sqllogictest v52.1.0 (/Users/adrian/GitHub/datafusion/datafusion/sqllogictest) + Compiling ffi_module_interface v0.1.0 (/Users/adrian/GitHub/datafusion/datafusion-examples/examples/ffi/ffi_module_interface) + Compiling ffi_example_table_provider v0.1.0 (/Users/adrian/GitHub/datafusion/datafusion-examples/examples/ffi/ffi_example_table_provider) + Compiling ffi_module_loader v0.1.0 (/Users/adrian/GitHub/datafusion/datafusion-examples/examples/ffi/ffi_module_loader) + Finished `test` profile [unoptimized + debuginfo] target(s) in 44.21s + Running unittests src/lib.rs (target/debug/deps/datafusion-2e26d3f4982bbdb4) + +running 406 tests +test datasource::file_format::avro::tests::read_binary_alltypes_plain_avro ... ok +test dataframe::parquet::tests::test_file_output_mode_directory ... ok +test dataframe::parquet::tests::test_file_output_mode_single_file ... ok +test datasource::file_format::avro::tests::read_bool_alltypes_plain_avro ... ok +test dataframe::parquet::tests::test_file_output_mode_automatic ... ok +test datasource::file_format::arrow::tests::test_write_empty_arrow_from_record_batch ... ok +test datasource::file_format::arrow::tests::test_write_empty_arrow_from_sql ... ok +test dataframe::parquet::tests::filter_pushdown_dataframe ... ok +test datasource::file_format::avro::tests::read_f32_alltypes_plain_avro ... ok +test datasource::file_format::avro::tests::read_i32_alltypes_plain_avro ... ok +test datasource::file_format::avro::tests::read_f64_alltypes_plain_avro ... ok +test datasource::file_format::avro::tests::read_i96_alltypes_plain_avro ... ok +test datasource::file_format::avro::tests::read_limit ... ok +test datasource::file_format::avro::tests::read_null_binary_alltypes_plain_avro ... ok +test datasource::file_format::avro::tests::read_null_bool_alltypes_plain_avro ... ok +test datasource::file_format::csv::tests::infer_schema_truncated_rows_false_error ... ok +test datasource::file_format::avro::tests::read_null_i32_alltypes_plain_avro ... ok +test datasource::file_format::avro::tests::read_null_string_alltypes_plain_avro ... ok +test datasource::file_format::avro::tests::read_small_batches ... ok +test datasource::file_format::csv::tests::infer_schema_with_truncated_rows_true ... ok +test datasource::file_format::csv::tests::infer_schema_with_null_regex ... ok +test datasource::file_format::csv::tests::query_compress_data::case_1 ... ok +test datasource::file_format::csv::tests::query_compress_data::case_2 ... ok +test datasource::file_format::csv::tests::infer_schema ... ok +test datasource::file_format::csv::tests::query_compress_data::case_3 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_1_1::line_count_1_0 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_1_1::line_count_2_5 ... ok +test datasource::file_format::csv::tests::read_limit ... ok +test datasource::file_format::csv::tests::query_compress_data::case_5 ... ok +test datasource::file_format::csv::tests::query_compress_data::case_4 ... ok +test dataframe::parquet::tests::roundtrip_parquet_with_encryption::allow_single_file_parallelism_2_true ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_3_17::line_count_1_0 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_2_5::line_count_1_0 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_1_1::line_count_3_93 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_2_5::line_count_2_5 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_1_1::line_count_1_0 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_3_17::line_count_2_5 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_2_5::line_count_3_93 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_with_finish::batch_size_3_17::line_count_3_93 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_2_5::line_count_1_0 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_1_1::line_count_2_5 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_2_5::line_count_2_5 ... ok +test dataframe::parquet::tests::roundtrip_parquet_with_encryption::allow_single_file_parallelism_1_false ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_3_17::line_count_1_0 ... ok +test datasource::file_format::csv::tests::read_char_column ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_3_17::line_count_2_5 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_3_17::line_count_3_93 ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_1_1::line_count_3_93 ... ok +test datasource::file_format::csv::tests::read_small_batches ... ok +test datasource::file_format::csv::tests::test_csv_deserializer_without_finish::batch_size_2_5::line_count_3_93 ... ok +test datasource::file_format::csv::tests::test_csv_extension_uncompressed ... ok +test datasource::file_format::csv::tests::test_csv_extension_compressed ... ok +test dataframe::parquet::tests::write_parquet_with_compression ... ok +test datasource::file_format::csv::tests::test_csv_multiple_empty_files ... ok +test datasource::file_format::csv::tests::test_csv_empty_file ... ok +test datasource::file_format::csv::tests::query_compress_csv ... ok +test datasource::file_format::avro::tests::read_alltypes_plain_avro ... ok +test datasource::file_format::csv::tests::test_csv_parallel_compressed::case_1 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_basic::case_2 ... ok +test datasource::file_format::csv::tests::test_csv_empty_with_header ... ok +test datasource::file_format::csv::tests::test_csv_parallel_basic::case_1 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_basic::case_3 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_compressed::case_2 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_basic::case_4 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_one_col::case_2 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_one_col::case_1 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_newlines_in_values::case_1 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_newlines_in_values::case_3 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_newlines_in_values::case_4 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_compressed::case_4 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_one_col::case_3 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_newlines_in_values::case_2 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_some_file_empty::case_1 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_some_file_empty::case_2 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_compressed::case_3 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_one_col::case_4 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_some_file_empty::case_4 ... ok +test datasource::file_format::csv::tests::test_decoder_truncated_rows_runtime ... ok +test datasource::file_format::csv::tests::test_infer_schema_escape_chars ... ok +test datasource::file_format::csv::tests::test_csv_parallel_some_file_empty::case_3 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_one_col::case_5 ... ok +test datasource::file_format::csv::tests::test_infer_schema_stream_null_chunks ... ok +test datasource::file_format::csv::tests::test_csv_serializer ... ok +test datasource::file_format::csv::tests::test_infer_schema_with_zero_max_records ... ok +test datasource::file_format::csv::tests::test_csv_serializer_no_header ... ok +test datasource::file_format::json::tests::infer_schema ... ok +test datasource::file_format::json::tests::infer_schema_with_limit ... ok +test datasource::file_format::csv::tests::test_csv_some_empty_with_header ... ok +test datasource::file_format::csv::tests::test_read_csv_truncated_rows_via_tempfile ... ok +test datasource::file_format::csv::tests::test_write_empty_csv_from_record_batch ... ok +test datasource::file_format::json::tests::it_can_read_empty_ndjson ... ok +test datasource::file_format::csv::tests::test_infer_schema_stream ... ok +test datasource::file_format::csv::tests::test_write_empty_csv_from_sql ... ok +test datasource::file_format::csv::tests::test_csv_parallel_one_col::case_6 ... ok +test datasource::file_format::json::tests::read_int_column ... ok +test datasource::file_format::json::tests::read_limit ... ok +test datasource::file_format::json::tests::test_json_deserializer_no_finish ... ok +test datasource::file_format::json::tests::test_json_deserializer_finish ... ok +test datasource::file_format::json::tests::read_small_batches ... ok +test datasource::file_format::json::tests::test_write_empty_json_from_record_batch ... ok +test datasource::file_format::json::tests::it_can_read_ndjson_in_parallel::case_1 ... ok +test datasource::file_format::json::tests::test_write_empty_json_from_sql ... ok +test datasource::file_format::json::tests::it_can_read_ndjson_in_parallel::case_2 ... ok +test datasource::file_format::parquet::tests::parquet_sink_parallel_write ... ok +test datasource::file_format::parquet::tests::parquet_sink_write ... ok +test datasource::file_format::parquet::tests::is_schema_stable ... ok +test datasource::file_format::parquet::tests::capture_bytes_scanned_metric ... ok +test datasource::file_format::json::tests::it_can_read_ndjson_in_parallel::case_3 ... ok +test datasource::file_format::parquet::tests::parquet_sink_write_partitions ... ok +test datasource::file_format::json::tests::it_can_read_ndjson_in_parallel::case_4 ... ok +test datasource::file_format::parquet::tests::parquet_sink_write_with_extension ... ok +test datasource::file_format::parquet::tests::parquet_sink_write_insert_schema_into_metadata ... ok +test datasource::file_format::parquet::tests::parquet_sink_write_with_folder_ending ... ok +test datasource::file_format::parquet::tests::parquet_sink_write_with_directory_name ... ok +test datasource::file_format::parquet::tests::read_binary_alltypes_plain_parquet ... ok +test datasource::file_format::parquet::tests::read_binaryview_alltypes_plain_parquet ... ok +test datasource::file_format::parquet::tests::read_bool_alltypes_plain_parquet ... ok +test datasource::file_format::parquet::tests::read_f32_alltypes_plain_parquet ... ok +test datasource::file_format::parquet::tests::read_f64_alltypes_plain_parquet ... ok +test datasource::file_format::parquet::tests::read_i32_alltypes_plain_parquet ... ok +test datasource::file_format::parquet::tests::read_i96_alltypes_plain_parquet ... ok +test datasource::file_format::parquet::tests::read_alltypes_plain_parquet ... ok +test datasource::file_format::parquet::tests::read_limit ... ok +test datasource::file_format::parquet::tests::read_small_batches ... ok +test datasource::file_format::parquet::tests::test_read_empty_parquet ... ok +test datasource::file_format::parquet::tests::test_read_partitioned_empty_parquet ... ok +test datasource::file_format::parquet::tests::read_merged_batches ... ok +test datasource::file_format::parquet::tests::fetch_metadata_with_size_hint ... ok +test datasource::file_format::parquet::tests::read_decimal_parquet ... ok +test datasource::file_format::parquet::tests::test_statistics_from_parquet_metadata_dictionary ... ok +test datasource::listing::table::tests::infer_preserves_provided_schema ... ok +test datasource::file_format::parquet::tests::test_write_empty_parquet_from_sql ... ok +test datasource::file_format::parquet::tests::test_write_empty_recordbatch_creates_file ... ok +test datasource::listing::table::tests::read_empty_table ... ok +test datasource::file_format::parquet::tests::test_statistics_from_parquet_metadata ... ok +test datasource::listing::table::tests::test_basic_table_scan ... ok +test datasource::file_format::tests::write_parquet_results_error_handling ... ok +test datasource::listing::table::tests::read_single_file ... ok +test datasource::listing::table::tests::test_insert_into_append_new_parquet_files_invalid_session_fails ... ok +test datasource::file_format::parquet::tests::test_read_parquet_page_index ... ok +test datasource::listing::table::tests::test_infer_options_compressed_csv ... ok +test datasource::file_format::csv::tests::test_csv_parallel_wide_rows::case_1 ... ok +test datasource::listing::table::tests::test_insert_into_sql_csv_defaults_header_row ... ok +test datasource::listing::table::tests::test_insert_into_sql_csv_defaults ... ok +test datasource::listing::table::tests::test_insert_into_sql_json_defaults ... ok +test datasource::listing::table::tests::test_listing_table_prunes_extra_files_in_hive ... ok +test datasource::listing::table::tests::test_list_files_configurations ... ok +test datasource::listing::table::tests::test_insert_into_append_new_parquet_files_session_overrides ... ok +test datasource::listing::table::tests::test_listing_table_config_with_multiple_files_comprehensive ... ok +test datasource::listing::table::tests::test_schema_source_tracking_comprehensive ... ok +test datasource::listing_table_factory::tests::test_create_using_folder_with_compression ... ok +test datasource::listing_table_factory::tests::test_create_using_folder_without_compression ... ok +test datasource::listing::table::tests::test_try_create_output_ordering ... ok +test datasource::listing::table::tests::test_table_stats_behaviors ... ok +test datasource::listing::table::tests::test_insert_into_sql_parquet_defaults ... ok +test datasource::listing::table::tests::test_insert_into_sql_parquet_session_overrides ... ok +test datasource::listing_table_factory::tests::test_create_using_non_std_file_ext_csv_options ... ok +test datasource::memory_test::tests::test_insert_from_empty_table ... ok +test datasource::listing_table_factory::tests::test_create_using_non_std_file_ext ... ok +test datasource::listing_table_factory::tests::test_odd_directory_names ... ok +test datasource::memory_test::tests::test_insert_into_single_partition ... ok +test datasource::memory_test::tests::test_insert_into_single_partition_with_multi_partition ... ok +test datasource::memory_test::tests::test_insert_into_multi_partition_with_multi_partition ... ok +test datasource::listing_table_factory::tests::test_create_with_hive_partitions ... ok +test datasource::memory_test::tests::test_insert_into_zero_partition ... ok +test datasource::memory_test::tests::test_invalid_projection ... ok +test datasource::memory_test::tests::test_schema_validation_incompatible_column ... ok +test datasource::memory_test::tests::test_schema_validation_different_column_count ... ok +test datasource::memory_test::tests::test_without_projection ... ok +test datasource::memory_test::tests::test_with_projection ... ok +test datasource::memory_test::tests::test_merged_schema ... ok +test datasource::physical_plan::avro::tests::avro_exec_missing_column ... ok +test datasource::physical_plan::avro::tests::avro_exec_with_partition ... ok +test datasource::physical_plan::avro::tests::avro_exec_without_partition ... ok +test datasource::listing_table_factory::tests::test_statistics_cache_prewarming ... ok +test datasource::physical_plan::avro::tests::test_chunked_avro::chunk_size_4_40 ... ok +test datasource::physical_plan::avro::tests::test_chunked_avro::chunk_size_3_30 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_limit::case_1 ... ok +test datasource::physical_plan::avro::tests::test_chunked_avro::chunk_size_2_20 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_limit::case_2 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_missing_column::case_1 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_wide_rows::case_2 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_limit::case_4 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_limit::case_5 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_missing_column::case_2 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_limit::case_3 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_missing_column::case_5 ... ok +test datasource::file_format::parquet::tests::parquet_sink_write_memory_reservation ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_mixed_order_projection::case_1 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_missing_column::case_3 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_missing_column::case_4 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_mixed_order_projection::case_5 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_mixed_order_projection::case_2 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_partition::case_2 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_partition::case_1 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_mixed_order_projection::case_4 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_mixed_order_projection::case_3 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_partition::case_5 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_projection::case_1 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_partition::case_4 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_projection::case_2 ... ok +test datasource::physical_plan::avro::tests::test_chunked_avro::chunk_size_1_10 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_partition::case_3 ... ok +test datasource::listing::table::tests::test_insert_into_parameterized ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_projection::case_5 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_projection::case_4 ... ok +test datasource::physical_plan::csv::tests::csv_exec_with_projection::case_3 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_wide_rows::case_3 ... ok +test datasource::file_format::csv::tests::test_csv_parallel_wide_rows::case_4 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_1::chunk_size_4_40 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_2::chunk_size_4_40 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_2::chunk_size_3_30 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_1::chunk_size_3_30 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_2::chunk_size_2_20 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_3::chunk_size_3_30 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_3::chunk_size_2_20 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_1::chunk_size_2_20 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_3::chunk_size_4_40 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_2::chunk_size_1_10 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_4::chunk_size_3_30 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_4::chunk_size_2_20 ... ok +test datasource::physical_plan::csv::tests::test_create_external_table_with_terminator ... ok +test datasource::physical_plan::csv::tests::test_create_external_table_with_terminator_with_newlines_in_values ... ok +test datasource::physical_plan::csv::tests::test_no_trailing_delimiter ... ok +test datasource::physical_plan::csv::tests::test_terminator ... ok +test dataframe::parquet::tests::write_parquet_with_small_rg_size ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_mixed_order_projection::case_1 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_3::chunk_size_1_10 ... ok +test datasource::physical_plan::csv::tests::write_csv_results_error_handling ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_5::chunk_size_3_30 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_mixed_order_projection::case_2 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_mixed_order_projection::case_3 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_mixed_order_projection::case_5 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_mixed_order_projection::case_4 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_projection::case_1 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_projection::case_2 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_projection::case_3 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_projection::case_5 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_with_missing_column::case_1 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_projection::case_4 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_with_missing_column::case_2 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_with_missing_column::case_3 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_without_projection::case_1 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_with_missing_column::case_5 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_with_missing_column::case_4 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_without_projection::case_2 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_without_projection::case_5 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_without_projection::case_4 ... ok +test datasource::physical_plan::json::tests::nd_json_exec_file_without_projection::case_3 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_4::chunk_size_4_40 ... ok +test datasource::physical_plan::json::tests::ndjson_schema_infer_max_records ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_1::chunk_size_3_30 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_1::chunk_size_2_20 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_1::chunk_size_4_40 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_2::chunk_size_1_10 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_5::chunk_size_2_20 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_5::chunk_size_4_40 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_1::chunk_size_1_10 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_2::chunk_size_4_40 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_2::chunk_size_2_20 ... ok +test datasource::physical_plan::csv::tests::write_csv_results ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_2::chunk_size_3_30 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_3::chunk_size_3_30 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_3::chunk_size_4_40 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_3::chunk_size_1_10 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_4::chunk_size_4_40 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_4::chunk_size_3_30 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_4::chunk_size_2_20 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_5::chunk_size_1_10 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_4::chunk_size_1_10 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_5::chunk_size_4_40 ... ok +test datasource::physical_plan::json::tests::test_json_with_repartitioning::case_2_gzip ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_5::chunk_size_2_20 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_5::chunk_size_3_30 ... ok +test datasource::physical_plan::json::tests::test_chunked_json::case_3::chunk_size_2_20 ... ok +test datasource::physical_plan::json::tests::test_json_with_repartitioning::case_3_bzip2 ... ok +test datasource::physical_plan::json::tests::test_json_with_repartitioning::case_5_zstd ... ok +test datasource::physical_plan::json::tests::test_json_with_repartitioning::case_4_xz ... ok +test datasource::physical_plan::json::tests::write_json_results_error_handling ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_column_order_filter ... ok +test datasource::physical_plan::json::tests::write_json_results ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_column_type_filter_ints ... ok +test datasource::physical_plan::parquet::tests::evolved_schema ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_column_type_filter_strings ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_disjoint_schema_filter ... ok +test datasource::physical_plan::json::tests::test_json_with_repartitioning::case_1_uncompressed ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_disjoint_schema_with_filter_pushdown ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_column_type_filter_timestamp_units ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_incompatible_types ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_intersection ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_inconsistent_order ... ok +test datasource::physical_plan::parquet::tests::multi_column_predicate_pushdown ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_intersection_filter ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_projection ... ok +test datasource::physical_plan::parquet::tests::multi_column_predicate_pushdown_page_index_pushdown ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_display ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_with_error ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_intersection_filter_with_filter_pushdown ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_has_no_pruning_predicate_if_can_not_prune ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_with_projection ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_with_partition ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_metrics ... ok +test datasource::physical_plan::parquet::tests::evolved_schema_disjoint_schema_with_page_index_pushdown ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_with_int96_nested ... ok +test datasource::physical_plan::parquet::tests::test_metadata_size_hint ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_with_int96_from_spark ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_metrics_with_multiple_predicates ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_with_range ... ok +test datasource::physical_plan::parquet::tests::test_constant_dictionary_column_parquet ... ok +test datasource::physical_plan::parquet::tests::test_struct_filter_parquet ... ok +test datasource::physical_plan::parquet::tests::test_pushdown_with_file_column_order_mismatch ... ok +test datasource::physical_plan::parquet::tests::test_struct_filter_parquet_with_view_types ... ok +test datasource::physical_plan::parquet::tests::test_pushdown_with_missing_column_in_file ... ok +test datasource::physical_plan::parquet::tests::test_pushdown_with_missing_column_in_file_multiple_types ... ok +test datasource::physical_plan::parquet::tests::parquet_page_index_exec_metrics ... ok +test datasource::view_test::tests::create_view_return_empty_dataframe ... ok +test datasource::view_test::tests::create_view_plan ... ok +test datasource::tests::can_override_physical_expr_adapter ... ok +test datasource::view_test::tests::issue_3242 ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_4::chunk_size_1_10 ... ok +test datasource::physical_plan::parquet::tests::test_pushdown_with_missing_middle_column ... ok +test datasource::view_test::tests::create_or_replace_view ... ok +test datasource::view_test::tests::query_view_with_inline_alias ... ok +test datasource::view_test::tests::query_view ... ok +test datasource::physical_plan::parquet::tests::test_pushdown_with_missing_column_nested_conditions ... ok +test datasource::physical_plan::parquet::tests::parquet_exec_has_pruning_predicate_for_guarantees ... ok +test datasource::view_test::tests::query_join_views ... ok +test datasource::view_test::tests::query_view_with_alias ... ok +test datasource::view_test::tests::query_view_with_filter ... ok +test datasource::view_test::tests::limit_pushdown_view ... ok +test datasource::view_test::tests::filter_pushdown_view ... ok +test datasource::view_test::tests::query_view_with_projection ... ok +test execution::context::parquet::tests::read_dummy_folder ... ok +test execution::context::tests::catalogs_not_leaked ... ok +test execution::context::tests::create_variable_err ... ok +test execution::context::csv::tests::query_csv_with_custom_partition_extension ... ok +test execution::context::tests::create_variable_expr ... ok +test execution::context::parquet::tests::read_with_glob_path ... ok +test execution::context::parquet::tests::read_from_registered_table_with_glob_path ... ok +test execution::context::tests::custom_catalog_and_schema_and_information_schema ... ok +test execution::context::tests::custom_catalog_and_schema ... ok +test execution::context::parquet::tests::read_from_parquet_folder_table ... ok +test execution::context::tests::custom_query_planner ... ok +test execution::context::tests::cross_catalog_access ... ok +test execution::context::tests::custom_type_planner ... ok +test execution::context::parquet::tests::read_from_parquet_folder ... ok +test execution::context::tests::disabled_default_catalog_and_schema ... ok +test execution::context::tests::custom_catalog_and_schema_no_default ... ok +test execution::context::tests::preserve_session_context_id ... ok +test execution::context::parquet::tests::read_with_glob_path_issue_2465 ... ok +test execution::context::tests::remove_optimizer_rule ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_1::chunk_size_1_10 ... ok +test execution::context::tests::register_deregister ... ok +test execution::context::tests::shared_memory_and_disk_manager ... ok +test execution::context::tests::test_parse_duration ... ok +test execution::context::tests::sql_create_schema ... ok +test execution::context::tests::sql_create_catalog ... ok +test execution::session_state::tests::test_create_logical_expr_from_sql_expr ... ok +test execution::session_state::tests::test_session_state_with_default_features ... ok +test execution::context::parquet::tests::register_parquet_respects_collect_statistics_config ... ok +test execution::session_state::tests::test_from_existing ... ok +test execution::session_state::tests::test_session_state_with_optimizer_rules ... ok +test execution::session_state::tests::test_with_default_features_not_override ... ok +test execution::context::tests::send_context_to_threads ... ok +test execution::session_state::tests::test_with_table_factories ... ok +test physical_planner::tests::bad_extension_planner ... ok +test physical_planner::tests::default_extension_planner ... ok +test physical_planner::tests::error_during_extension_planning ... ok +test execution::session_state::tests::test_with_expr_planners ... ok +test physical_planner::tests::aggregate_with_alias ... ok +test datasource::physical_plan::parquet::tests::write_table_results ... ok +test physical_planner::tests::hash_agg_group_by_partitioned_on_dicts ... ok +test physical_planner::tests::subquery_alias_confusing_the_optimizer ... ok +test physical_planner::tests::test_aggregate_count_all_with_alias ... ok +test execution::context::parquet::tests::read_from_different_file_extension ... ok +test execution::context::tests::test_dynamic_file_query ... ok +test physical_planner::tests::test_aggregate_schema_check_passes ... ok +test physical_planner::tests::test_aggregate_schema_mismatch_field_name ... ok +test physical_planner::tests::hash_agg_group_by_partitioned ... ok +test physical_planner::tests::test_aggregate_schema_mismatch_field_metadata ... ok +test physical_planner::tests::test_aggregate_schema_mismatch_field_count ... ok +test physical_planner::tests::in_list_types_struct_literal ... ok +test physical_planner::tests::hash_agg_grouping_set_input_schema ... ok +test physical_planner::tests::test_aggregate_schema_mismatch_field_nullability ... ok +test physical_planner::tests::hash_agg_grouping_set_by_partitioned ... ok +test physical_planner::tests::hash_agg_input_schema ... ok +test physical_planner::tests::test_aggregate_schema_mismatch_metadata ... ok +test physical_planner::tests::test_aggregate_schema_mismatch_field_type ... ok +test physical_planner::tests::test_create_not ... ok +test physical_planner::tests::test_aggregate_schema_mismatch_multiple ... ok +test physical_planner::tests::test_invariant_checker_levels ... ok +test physical_planner::tests::test_explain ... ok +test physical_planner::tests::test_display_graphviz_with_statistics ... ok +test physical_planner::tests::test_display_plan_in_graphviz_format ... ok +test physical_planner::tests::test_explain_indent_err ... ok +test physical_planner::tests::test_optimization_invariant_checker ... ok +test physical_planner::tests::test_limit_with_partitions ... ok +test physical_planner::tests::in_list_types ... ok +test physical_planner::tests::test_create_rollup_expr ... ok +test physical_planner::tests::test_with_zero_offset_plan ... ok +test physical_planner::tests::test_with_csv_plan ... ok +test physical_planner::tests::test_create_cube_expr ... ok +test physical_planner::tests::test_all_operators ... ok +test physical_planner::tests::errors ... ok +test execution::context::tests::with_listing_schema_provider ... ok +test datasource::physical_plan::csv::tests::test_chunked_csv::case_5::chunk_size_1_10 ... ok + +test result: ok. 406 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.54s + + Running unittests src/bin/print_config_docs.rs (target/debug/deps/print_config_docs-c3d37bc743db0049) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/bin/print_functions_docs.rs (target/debug/deps/print_functions_docs-b99bcd4aeb0b12f6) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/bin/print_runtime_config_docs.rs (target/debug/deps/print_runtime_config_docs-eb79e74c0a4577bf) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/config_from_env.rs (target/debug/deps/config_from_env-8fedf15f08c7e612) + +running 1 test +test from_env ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/core_integration.rs (target/debug/deps/core_integration-d7aa893f529b99f4) + +running 876 tests +test catalog::memory::memory_catalog_dereg_missing ... ok +test catalog::memory::memory_catalog_dereg_empty_schema ... ok +test catalog::memory::memory_catalog_dereg_nonempty_schema_with_table_removal ... ok +test catalog::memory::test_mem_provider ... ok +test catalog::memory::memory_catalog_dereg_nonempty_schema ... ok +test catalog::memory::default_register_schema_not_supported ... ok +test catalog_listing::pruned_partition_list::test_list_partition ... ok +test catalog_listing::pruned_partition_list::test_pruned_partition_list_empty ... ok +test catalog_listing::pruned_partition_list::test_pruned_partition_list ... ok +test catalog_listing::pruned_partition_list::test_pruned_partition_list_multi ... ok +test custom_sources_cases::dml_planning::test_unsupported_table_truncate ... ok +test custom_sources_cases::dml_planning::test_unsupported_table_delete ... ok +test custom_sources_cases::dml_planning::test_delete_no_filters ... ok +test custom_sources_cases::dml_planning::test_delete_complex_expr ... ok +test custom_sources_cases::dml_planning::test_delete_multiple_filters ... ok +test custom_sources_cases::dml_planning::test_delete_single_filter ... ok +test custom_sources_cases::dml_planning::test_truncate_calls_provider ... ok +test custom_sources_cases::dml_planning::test_unsupported_table_update ... ok +test custom_sources_cases::dml_planning::test_update_assignments ... ok +test custom_sources_cases::custom_source_dataframe ... ok +test custom_sources_cases::statistics::sql_basic ... ok +test custom_sources_cases::statistics::sql_filter ... ok +test custom_sources_cases::statistics::sql_limit ... ok +test custom_sources_cases::optimizers_catch_all_statistics ... ok +test custom_sources_cases::statistics::sql_window ... ok +test dataframe::dataframe_functions::test_count_wildcard_with_alias ... ok +test custom_sources_cases::provider_filter_pushdown::test_filter_pushdown_results ... ok +test dataframe::aggregate_assert_no_empty_batches ... ok +test dataframe::cache_producer_test ... ok +test dataframe::dataframe_functions::test_fn_array_to_string ... ok +test dataframe::dataframe_functions::test_fn_approx_median ... ok +test dataframe::consecutive_projection_same_schema ... ok +test dataframe::dataframe_functions::test_cast ... ok +test dataframe::cast_expr_test ... ok +test dataframe::dataframe_functions::test_count_wildcard ... ok +test catalog::memory::test_schema_register_listing_table ... ok +test dataframe::aggregate ... ok +test dataframe::dataframe_functions::test_fn_arrow_typeof ... ok +test dataframe::dataframe_functions::test_fn_btrim ... ok +test dataframe::dataframe_functions::test_fn_character_length ... ok +test dataframe::dataframe_functions::test_fn_bit_length ... ok +test dataframe::boolean_dictionary_as_filter ... ok +test dataframe::dataframe_functions::test_fn_chr ... ok +test dataframe::dataframe_functions::test_fn_ascii ... ok +test dataframe::dataframe_functions::test_fn_coalesce ... ok +test dataframe::dataframe_functions::test_fn_encode ... ok +test dataframe::dataframe_functions::test_fn_ends_with ... ok +test dataframe::dataframe_functions::test_fn_btrim_with_chars ... ok +test dataframe::dataframe_functions::test_fn_decode ... ok +test dataframe::dataframe_functions::test_fn_left ... ok +test dataframe::dataframe_functions::test_fn_arrow_cast ... ok +test dataframe::dataframe_functions::test_fn_initcap ... ok +test dataframe::dataframe_functions::test_fn_lpad ... ok +test dataframe::dataframe_functions::test_fn_lpad_with_string ... ok +test dataframe::dataframe_functions::test_fn_lower ... ok +test dataframe::dataframe_functions::test_fn_ltrim ... ok +test dataframe::dataframe_functions::test_fn_ltrim_with_columns ... ok +test dataframe::dataframe_functions::test_fn_map ... ok +test dataframe::dataframe_functions::test_fn_named_struct ... ok +test dataframe::dataframe_functions::test_fn_repeat ... ok +test dataframe::dataframe_functions::test_fn_md5 ... ok +test dataframe::dataframe_functions::test_fn_replace ... ok +test dataframe::dataframe_functions::test_fn_nullif ... ok +test dataframe::dataframe_functions::test_fn_reverse ... ok +test dataframe::dataframe_functions::test_fn_rpad_with_characters ... ok +test dataframe::dataframe_functions::test_fn_regexp_like ... ok +test dataframe::dataframe_functions::test_fn_split_part ... ok +test dataframe::dataframe_functions::test_fn_starts_with ... ok +test dataframe::dataframe_functions::test_fn_regexp_match ... ok +test dataframe::dataframe_functions::test_fn_regexp_replace ... ok +test dataframe::dataframe_functions::test_fn_rpad ... ok +test dataframe::dataframe_functions::test_fn_strpos ... ok +test dataframe::dataframe_functions::test_fn_struct ... ok +test dataframe::cache_test ... ok +test dataframe::dataframe_functions::test_fn_substr ... ok +test dataframe::dataframe_functions::test_fn_right ... ok +test dataframe::dataframe_functions::test_fn_upper ... ok +test dataframe::dataframe_functions::test_fn_sha224 ... ok +test dataframe::dataframe_functions::test_fn_approx_percentile_cont ... ok +test dataframe::dataframe_functions::test_fn_to_hex ... ok +test dataframe::dataframe_functions::test_fn_translate ... ok +test dataframe::dataframe_functions::test_nvl2 ... ok +test dataframe::dense_union_is_null ... ok +test dataframe::dataframe_functions::test_nvl ... ok +test dataframe::dataframe_functions::test_nvl2_short_circuit ... ok +test dataframe::drop_columns ... ok +test dataframe::drop_columns_with_duplicates ... ok +test dataframe::drop_columns_with_nonexistent_columns ... ok +test dataframe::drop_columns_qualified ... ok +test dataframe::drop_columns_with_empty_array ... ok +test dataframe::drop_with_periods ... ok +test dataframe::drop_with_quotes ... ok +test dataframe::except ... ok +test dataframe::filter_on_ambiguous_column ... ok +test dataframe::drop_columns_qualified_find_qualified ... ok +test dataframe::except_distinct ... ok +test dataframe::explain ... ok +test dataframe::group_by_ambiguous_column ... ok +test dataframe::filter_with_alias_overwrite ... ok +test dataframe::intersect_distinct ... ok +test dataframe::intersect ... ok +test dataframe::join_ambiguous_filter ... ok +test dataframe::join2 ... ok +test dataframe::df_count ... ok +test dataframe::join_on ... ok +test dataframe::join_coercion_unnamed ... ok +test dataframe::join_on_filter_datatype ... ok +test dataframe::nested_explain_should_fail ... ok +test dataframe::limit ... ok +test dataframe::register_non_avro_file ... ok +test dataframe::register_non_csv_file ... ok +test dataframe::describe::describe_boolean_binary ... ok +test dataframe::register_non_json_file ... ok +test dataframe::filtered_aggr_with_param_values ... ok +test dataframe::register_non_parquet_file ... ok +test dataframe::describe::describe_null ... ok +test dataframe::registry ... ok +test dataframe::register_temporary_table ... ok +test dataframe::right_anti_filter_push_down ... ok +test dataframe::row_writer_resize_test ... ok +test dataframe::join_with_alias_filter ... ok +test dataframe::select_ambiguous_column ... ok +test dataframe::right_semi_with_alias_filter ... ok +test dataframe::select_columns ... ok +test dataframe::select_all ... ok +test dataframe::select_columns_with_nonexistent_columns ... ok +test dataframe::select_exprs ... ok +test dataframe::select_expr ... ok +test dataframe::select_with_periods ... ok +test dataframe::select_with_alias_overwrite ... ok +test dataframe::sendable ... ok +test dataframe::select_with_window_exprs ... ok +test dataframe::sort_on_ambiguous_column ... ok +test dataframe::sort_on_distinct_unprojected_columns ... ok +test dataframe::sort_on_unprojected_columns ... ok +test dataframe::sort_on_distinct_columns ... ok +test dataframe::test_aggregate_name_collision ... ok +test dataframe::sparse_union_is_null ... ok +test dataframe::test_aggregate_with_pk ... ok +test dataframe::register_table ... ok +test dataframe::test_aggregate_with_pk2 ... ok +test dataframe::test_aggregate_with_pk3 ... ok +test dataframe::join ... ok +test dataframe::test_alias_empty ... ok +test dataframe::test_aggregate_with_pk4 ... ok +test dataframe::test_alias_nested ... ok +test dataframe::test_alias_self_join ... ok +test dataframe::test_alias ... ok +test dataframe::test_alias_with_metadata ... ok +test dataframe::test_aggregate_subexpr ... ok +test dataframe::test_aggregate_alias ... ok +test dataframe::test_array_agg ... ok +test dataframe::drop_columns_duplicated_names_from_different_qualifiers ... ok +test dataframe::test_array_agg_distinct_schema ... ok +test dataframe::test_cache_mismatch ... ok +test dataframe::test_coalesce_from_values_schema_multiple_rows ... ok +test dataframe::test_coalesce_schema ... ok +test dataframe::test_coalesce_from_values_schema ... ok +test dataframe::describe_lookup_via_quoted_identifier ... ok +test dataframe::test_copy_schema ... ok +test dataframe::test_array_agg_ord_schema ... ok +test dataframe::test_copy_to_preserves_order ... ok +test dataframe::test_array_agg_schema ... ok +test dataframe::test_count_wildcard_on_where_exist ... ok +test dataframe::test_dataframe_from_columns ... ok +test dataframe::test_count_wildcard_on_window ... ok +test dataframe::test_dataframe_macro ... ok +test dataframe::test_count_wildcard_on_aggregate ... ok +test dataframe::test_dataframe_placeholder_column_parameter ... ok +test dataframe::test_aggregate_with_union ... ok +test dataframe::test_count_wildcard_on_sort ... ok +test dataframe::test_dataframe_placeholder_like_expression ... ok +test dataframe::test_distinct_on_sort_by_unprojected ... ok +test dataframe::non_partition_aware_union ... ok +test dataframe::test_distinct_sort_by_unprojected ... ok +test dataframe::test_distinct ... ok +test dataframe::partition_aware_union ... ok +test dataframe::test_dataframe_placeholder_missing_param_values ... ok +test dataframe::test_find_qualified_names ... ok +test dataframe::test_duplicate_state_fields_for_dfschema_construct ... ok +test dataframe::test_count_wildcard_on_where_in ... ok +test dataframe::test_fill_null ... ok +test dataframe::test_except_nested_struct ... ok +test dataframe::test_fill_null_all_columns ... ok +test dataframe::select_columns_duplicated_names_from_different_qualifiers ... ok +test dataframe::test_insert_into_checking ... ok +test dataframe::test_read_batches ... ok +test dataframe::test_read_batches_empty ... ok +test dataframe::test_count_wildcard_on_where_scalar_subquery ... ok +test dataframe::test_insert_into_casting_support ... ok +test dataframe::test_select_over_aggregate_schema ... ok +test dataframe::test_grouping_sets ... ok +test dataframe::test_distinct_on_sort_by ... ok +test dataframe::union_literal_is_null_and_not_null ... ok +test dataframe::test_distinct_on ... ok +test dataframe::unnest_analyze_metrics ... ok +test dataframe::test_distinct_sort_by ... ok +test dataframe::unnest_aggregate_columns ... ok +test dataframe::unnest_column_nulls ... ok +test dataframe::test_union_by_name ... ok +test dataframe::test_union_by_name_distinct ... ok +test dataframe::union_with_mix_of_presorted_and_explicitly_resorted_inputs_with_repartition_sorts_false ... ok +test dataframe::union_with_mix_of_presorted_and_explicitly_resorted_inputs_with_repartition_sorts_true ... ok +test dataframe::unnest_array_agg ... ok +test dataframe::unnest_fixed_list_drop_nulls ... ok +test dataframe::unnest_fixed_list_non_null ... ok +test dataframe::unnest_fixed_list ... ok +test dataframe::unnest_non_nullable_list ... ok +test dataframe::unnest_dict_encoded_columns ... ok +test dataframe::use_var_provider ... ok +test dataframe::unnest_multiple_columns ... ok +test dataframe::unnest_with_redundant_columns ... ok +test dataframe::unnest_no_empty_batches ... ok +test dataframe::with_column_name ... ok +test dataframe::window_aggregates_with_filter ... ok +test dataframe::with_column_renamed_ambiguous ... ok +test dataframe::unnest_columns ... ok +test dataframe::test_window_function_with_column ... ok +test dataframe::with_column_window_functions ... ok +test dataframe::write_csv_with_order ... ok +test dataframe::test_grouping_sets_count ... ok +test dataframe::test_grouping_set_array_agg_with_overflow ... ok +test dataframe::write_json_with_order ... ok +test dataframe::with_column_renamed ... ok +test dataframe::window_using_aggregates ... ok +test dataframe::with_column_renamed_case_sensitive ... ok +test dataframe::write_parquet_with_order ... ok +test dataframe::write_partitioned_parquet_results::case_2 ... ok +test datasource::object_store_access::create_multi_file_csv_file ... ok +test dataframe::write_partitioned_parquet_results::case_3 ... ok +test datasource::object_store_access::create_single_csv_file ... ok +test dataframe::write_partitioned_parquet_results::case_1 ... ok +test datasource::object_store_access::create_single_parquet_file_default ... ok +test datasource::object_store_access::create_single_parquet_file_prefetch ... ok +test datasource::object_store_access::create_single_parquet_file_no_prefetch ... ok +test datasource::object_store_access::create_single_parquet_file_small_prefetch ... ok +test datasource::object_store_access::create_single_parquet_file_too_small_prefetch ... ok +test dataframe::write_table_with_order ... ok +test datasource::object_store_access::query_single_csv_file ... ok +test dataframe::write_parquet_results ... ok +test datasource::object_store_access::query_single_parquet_file ... ok +test dataframe::with_column ... ok +test datasource::object_store_access::query_multi_csv_file ... ok +test datasource::csv::test_csv_schema_inference_different_column_counts ... ok +test dataframe::with_column_join_same_columns ... ok +test datasource::object_store_access::query_single_parquet_file_multi_row_groups_multiple_predicates ... ok +test datasource::object_store_access::multi_query_multi_file_csv_file ... ok +test dataframe::verify_join_output_partitioning ... ok +test datasource::object_store_access::query_single_parquet_file_with_single_predicate ... ok +test dataframe::with_column_renamed_join ... ok +test datasource::object_store_access::query_partitioned_csv_file ... ok +test execution::coop::filter_reject_all_batches_yields::pretend_infinite_2_true ... ok +test execution::coop::agg_no_grouping_yields::pretend_infinite_2_true ... ok +test execution::coop::agg_no_grouping_yields::pretend_infinite_1_false ... ok +test execution::coop::filter_yields::pretend_infinite_1_false ... ok +test execution::coop::filter_reject_all_batches_yields::pretend_infinite_1_false ... ok +test execution::coop::agg_grouping_yields::pretend_infinite_2_true ... ok +test execution::coop::hash_join_without_repartition_and_no_agg::pretend_infinite_1_false ... ok +test execution::coop::agg_grouping_yields::pretend_infinite_1_false ... ok +test execution::coop::filter_yields::pretend_infinite_2_true ... ok +test execution::coop::join_agg_yields::pretend_infinite_1_false ... ok +test execution::coop::join_yields::pretend_infinite_1_false ... ok +test execution::coop::join_agg_yields::pretend_infinite_2_true ... ok +test execution::coop::join_yields::pretend_infinite_2_true ... ok +test execution::coop::hash_join_without_repartition_and_no_agg::pretend_infinite_2_true ... ok +test execution::coop::hash_join_yields::pretend_infinite_1_false ... ok +test execution::coop::hash_join_yields::pretend_infinite_2_true ... ok +test execution::coop::sort_yields::pretend_infinite_1_false ... ok +test execution::coop::spill_reader_stream_yield ... ok +test execution::datasource_split::datasource_empty_batch_clean_termination ... ok +test execution::datasource_split::datasource_multiple_empty_batches ... ok +test execution::datasource_split::datasource_exact_batch_size_no_split ... ok +test execution::datasource_split::datasource_small_batch_no_split ... ok +test execution::datasource_split::datasource_splits_large_batches ... ok +test execution::coop::sort_yields::pretend_infinite_2_true ... ok +test execution::logical_plan::inline_scan_projection_test ... ok +test execution::logical_plan::count_only_nulls ... ok +test execution::register_arrow::test_register_arrow_auto_detects_format ... ok +test expr_api::parse_sql_expr::roundtrip_qualified_schema ... ok +test expr_api::simplification::basic ... ok +test expr_api::simplification::fold_and_simplify ... ok +test expr_api::simplification::multiple_now ... ok +test expr_api::simplification::now_less_than_timestamp ... ok +test expr_api::simplification::now_simplification_with_and_without_start_time ... ok +test expr_api::simplification::select_date_plus_interval ... ok +test expr_api::simplification::simplify_project_scalar_fn ... ok +test expr_api::simplification::simplify_scan_predicate ... ok +test expr_api::simplification::test_const_evaluator ... ok +test expr_api::simplification::test_const_evaluator_alias ... ok +test expr_api::simplification::test_const_evaluator_now ... ok +test expr_api::simplification::test_const_evaluator_scalar_functions ... ok +test expr_api::simplification::test_evaluator_udfs ... ok +test expr_api::simplification::test_simplify_concat ... ok +test expr_api::simplification::test_simplify_concat_ws ... ok +test expr_api::simplification::test_simplify_concat_ws_with_null ... ok +test expr_api::simplification::test_simplify_cycles ... ok +test expr_api::simplification::test_simplify_log ... ok +test expr_api::simplification::test_simplify_power ... ok +test expr_api::simplification::to_timestamp_expr_folded ... ok +test expr_api::test_aggregate_ext_distinct ... ok +test execution::register_arrow::test_register_arrow_join_file_and_stream ... ok +test expr_api::test_aggregate_ext_filter ... ok +test expr_api::test_aggregate_ext_null_treatment ... ok +test expr_api::test_create_physical_expr ... ok +test expr_api::test_aggregate_ext_order_by ... ok +test expr_api::test_create_physical_expr_nvl2 ... ok +test expr_api::test_eq ... ok +test expr_api::test_create_physical_expr_coercion ... ok +test expr_api::test_eq_with_coercion ... ok +test expr_api::test_get_field_null ... ok +test expr_api::test_get_field ... ok +test expr_api::test_list_index ... ok +test expr_api::parse_sql_expr::round_trip_parse_sql_expr ... ok +test expr_api::test_list_range ... ok +test expr_api::test_octet_length ... ok +test expr_api::test_nested_get_field ... ok +test execution::coop::interleave_then_aggregate_yields::pretend_infinite_1_false ... ok +test macro_hygiene::config_field::test_macro ... ok +test macro_hygiene::config_namespace::test_macro ... ok +test macro_hygiene::plan_datafusion_err::test_macro ... ok +test macro_hygiene::plan_err::test_macro ... ok +test macro_hygiene::record_batch::test_macro ... ok +test execution::coop::interleave_then_aggregate_yields::pretend_infinite_2_true ... ok +test execution::coop::interleave_then_filter_all_yields::pretend_infinite_1_false ... ok +test execution::coop::interleave_then_filter_all_yields::pretend_infinite_2_true ... ok +test memory_limit::group_by_hash ... ok +test memory_limit::cross_join ... ok +test memory_limit::group_by_none ... ok +test memory_limit::group_by_row_hash ... ok +test memory_limit::join_by_expression ... ok +test memory_limit::join_by_key_multiple_partitions ... ok +test memory_limit::join_by_key_single_partition ... ok +test memory_limit::oom_grouped_hash_aggregate ... ok +test memory_limit::oom_recursive_cte ... ok +test memory_limit::oom_sort ... ok +test memory_limit::oom_parquet_sink ... ok +test memory_limit::oom_with_tracked_consumer_pool ... ok +test memory_limit::sort_preserving_merge ... ok +test memory_limit::sort_merge_join_spill ... ok +test memory_limit::sort_spill_reservation ... ok +test memory_limit::sort_merge_join_no_spill ... ok +test memory_limit::symmetric_hash_join ... ok +test memory_limit::test_disk_spill_limit_not_reached ... ok +test execution::coop::sort_merge_join_yields::pretend_infinite_2_true ... ok +test execution::coop::sort_merge_join_yields::pretend_infinite_1_false ... ok +test execution::coop::agg_grouped_topk_yields::pretend_infinite_2_true ... ok +test execution::coop::agg_grouped_topk_yields::pretend_infinite_1_false ... ok +test optimizer::concat_literals ... ok +test optimizer::concat_ws_literals ... ok +test optimizer::select_arrow_cast ... ok +test optimizer::test_inequalities_non_null_bounded ... ok +test optimizer::test_nested_schema_nullability ... ok +test optimizer::timestamp_nano_ts_none_predicates ... ok +test optimizer::timestamp_nano_ts_utc_predicates ... ok +test physical_optimizer::aggregate_statistics::test_count_inexact_stat ... ok +test physical_optimizer::aggregate_statistics::test_count_partial_direct_child ... ok +test physical_optimizer::aggregate_statistics::test_count_partial_indirect_child ... ok +test physical_optimizer::aggregate_statistics::test_count_partial_with_nulls_direct_child ... ok +test physical_optimizer::aggregate_statistics::test_count_partial_with_nulls_indirect_child ... ok +test physical_optimizer::aggregate_statistics::test_count_with_nulls_inexact_stat ... ok +test physical_optimizer::aggregate_statistics::utf8_grouping_min_max_limit_fallbacks ... ok +test physical_optimizer::combine_partial_final_agg::aggregations_combined ... ok +test physical_optimizer::combine_partial_final_agg::aggregations_not_combined ... ok +test physical_optimizer::combine_partial_final_agg::aggregations_with_group_combined ... ok +test physical_optimizer::combine_partial_final_agg::aggregations_with_limit_combined ... ok +test physical_optimizer::enforce_distribution::added_repartition_to_single_partition ... ok +test memory_limit::repartition_mem_limit::test_repartition_memory_limit ... ok +test physical_optimizer::enforce_distribution::do_not_add_unnecessary_hash ... ok +test physical_optimizer::enforce_distribution::do_not_preserve_ordering_through_repartition ... ok +test physical_optimizer::enforce_distribution::do_not_add_unnecessary_hash2 ... ok +test physical_optimizer::enforce_distribution::do_not_preserve_ordering_through_repartition2 ... ok +test physical_optimizer::enforce_distribution::do_not_put_sort_when_input_is_invalid ... ok +test memory_limit::test_disk_spill_limit_reached ... ok +test physical_optimizer::enforce_distribution::do_not_preserve_ordering_through_repartition3 ... ok +test physical_optimizer::enforce_distribution::merge_does_not_need_sort ... ok +test physical_optimizer::enforce_distribution::hash_join_key_ordering ... ok +test physical_optimizer::enforce_distribution::join_after_agg_alias ... ok +test physical_optimizer::enforce_distribution::multi_joins_after_alias ... ok +test physical_optimizer::enforce_distribution::multi_joins_after_multi_alias ... ok +test physical_optimizer::enforce_distribution::multi_hash_join_key_ordering ... ok +test physical_optimizer::enforce_distribution::no_need_for_sort_after_filter ... ok +test physical_optimizer::enforce_distribution::optimize_away_unnecessary_repartition ... ok +test physical_optimizer::enforce_distribution::optimize_away_unnecessary_repartition2 ... ok +test physical_optimizer::enforce_distribution::multi_hash_joins ... ok +test physical_optimizer::enforce_distribution::parallelization_compressed_csv ... ok +test physical_optimizer::enforce_distribution::parallelization_does_not_benefit ... ok +test physical_optimizer::enforce_distribution::parallelization_ignores_transitively_with_projection_csv ... ok +test physical_optimizer::enforce_distribution::parallelization_ignores_transitively_with_projection_parquet ... ok +test physical_optimizer::enforce_distribution::parallelization_ignores_limit ... ok +test physical_optimizer::enforce_distribution::parallelization_limit_with_filter ... ok +test physical_optimizer::enforce_distribution::parallelization_prior_to_sort_preserving_merge ... ok +test physical_optimizer::enforce_distribution::parallelization_multiple_files ... ok +test physical_optimizer::enforce_distribution::parallelization_sort_preserving_merge_with_union ... ok +test physical_optimizer::enforce_distribution::parallelization_single_partition ... ok +test physical_optimizer::enforce_distribution::parallelization_sorted_limit ... ok +test physical_optimizer::enforce_distribution::parallelization_two_partitions ... ok +test physical_optimizer::enforce_distribution::parallelization_two_partitions_into_four ... ok +test physical_optimizer::enforce_distribution::multi_smj_joins ... ok +test physical_optimizer::enforce_distribution::parallelization_union_inputs ... ok +test physical_optimizer::enforce_distribution::put_sort_when_input_is_valid ... ok +test physical_optimizer::enforce_distribution::preserve_ordering_through_repartition ... ok +test physical_optimizer::enforce_distribution::remove_redundant_roundrobins ... ok +test physical_optimizer::enforce_distribution::remove_unnecessary_spm_after_filter ... ok +test physical_optimizer::enforce_distribution::repartition_deepest_node ... ok +test physical_optimizer::enforce_distribution::repartition_does_not_destroy_sort ... ok +test physical_optimizer::enforce_distribution::repartition_does_not_destroy_sort_more_complex ... ok +test physical_optimizer::enforce_distribution::repartition_ignores_limit ... ok +test physical_optimizer::enforce_distribution::repartition_ignores_sort_preserving_merge ... ok +test physical_optimizer::enforce_distribution::repartition_ignores_sort_preserving_merge_with_union ... ok +test physical_optimizer::enforce_distribution::repartition_ignores_transitively_with_projection ... ok +test physical_optimizer::enforce_distribution::repartition_ignores_union ... ok +test physical_optimizer::enforce_distribution::repartition_sorted_limit ... ok +test physical_optimizer::enforce_distribution::repartition_sorted_limit_with_filter ... ok +test physical_optimizer::enforce_distribution::repartition_through_sort_preserving_merge ... ok +test physical_optimizer::enforce_distribution::repartition_transitively_past_sort_with_filter ... ok +test physical_optimizer::enforce_distribution::repartition_transitively_past_sort_with_projection ... ok +test physical_optimizer::enforce_distribution::repartition_transitively_past_sort_with_projection_and_filter ... ok +test physical_optimizer::enforce_distribution::repartition_transitively_with_projection ... ok +test physical_optimizer::enforce_distribution::repartition_unsorted_limit ... ok +test physical_optimizer::enforce_distribution::smj_join_key_ordering ... ok +test physical_optimizer::enforce_distribution::reorder_join_keys_to_left_input ... ok +test physical_optimizer::enforce_distribution::test_distribute_sort_parquet ... ok +test physical_optimizer::enforce_distribution::test_replace_order_preserving_variants_with_fetch ... ok +test physical_optimizer::enforce_distribution::union_not_to_interleave ... ok +test physical_optimizer::enforce_distribution::test_distribute_sort_memtable ... ok +test physical_optimizer::enforce_sorting::test_add_required_sort ... ok +test physical_optimizer::enforce_sorting::test_change_wrong_sorting ... ok +test physical_optimizer::enforce_distribution::reorder_join_keys_to_right_input ... ok +test physical_optimizer::enforce_sorting::test_coalesce_propagate ... ok +test physical_optimizer::enforce_sorting::test_change_wrong_sorting2 ... ok +test physical_optimizer::enforce_distribution::union_to_interleave ... ok +test physical_optimizer::enforce_sorting::test_commutativity ... ok +test physical_optimizer::enforce_sorting::test_do_not_pushdown_through_limit ... ok +test physical_optimizer::enforce_sorting::test_do_not_pushdown_through_spm ... ok +test physical_optimizer::enforce_sorting::test_do_not_remove_sort_with_limit ... ok +test physical_optimizer::enforce_sorting::test_handles_multiple_orthogonal_sorts ... ok +test physical_optimizer::enforce_sorting::test_keeps_used_orthogonal_sort ... ok +test physical_optimizer::enforce_sorting::test_multilayer_coalesce_partitions ... ok +test physical_optimizer::enforce_sorting::test_not_replaced_with_partial_sort_for_bounded_input ... ok +test physical_optimizer::enforce_sorting::test_parallelize_sort_preserves_fetch ... ok +test physical_optimizer::enforce_sorting::test_not_replaced_with_partial_sort_for_unbounded_input ... ok +test physical_optimizer::enforce_sorting::test_push_with_required_input_ordering_allowed ... ok +test physical_optimizer::enforce_sorting::test_multiple_sort_window_exec ... ok +test physical_optimizer::enforce_sorting::test_push_with_required_input_ordering_prohibited ... ok +test physical_optimizer::enforce_sorting::test_partial_sort_with_homogeneous_batches ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort ... ok +test physical_optimizer::enforce_sorting::test_pushdown_through_spm ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort1 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort2 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort4 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort3 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort6 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort7 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort5 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort8 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_spm2 ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_spm1 ... ok +test physical_optimizer::enforce_sorting::test_removes_unused_orthogonal_sort ... ok +test physical_optimizer::enforce_sorting::test_remove_unnecessary_sort_window_multilayer ... ok +test physical_optimizer::enforce_sorting::test_replace_with_partial_sort ... ok +test physical_optimizer::enforce_sorting::test_replace_with_partial_sort2 ... ok +test physical_optimizer::enforce_sorting::test_soft_hard_requirements_multiple_sorts ... ok +test physical_optimizer::enforce_sorting::test_soft_hard_requirements_remove_soft_requirement ... ok +test physical_optimizer::enforce_sorting::test_soft_hard_requirements_multiple_soft_requirements ... ok +test physical_optimizer::enforce_sorting::test_soft_hard_requirements_with_multiple_soft_requirements_and_output_requirement ... ok +test physical_optimizer::enforce_sorting::test_soft_hard_requirements_remove_soft_requirement_without_pushdowns ... ok +test physical_optimizer::enforce_sorting::test_sort_merge_join_complex_order_by ... ok +test physical_optimizer::enforce_sorting::test_sort_merge_join_order_by_right ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted ... ok +test physical_optimizer::enforce_sorting::test_sort_with_streaming_table ... ok +test physical_optimizer::enforce_sorting::test_sort_merge_join_order_by_left ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted2 ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted4 ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted3 ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted5 ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted7 ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted8 ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_sorted ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted6 ... ok +test physical_optimizer::enforce_sorting::test_union_inputs_different_sorted_with_limit ... ok +test physical_optimizer::enforce_sorting::test_window_multi_path_sort ... ok +test physical_optimizer::enforce_sorting::test_window_multi_layer_requirement ... ok +test physical_optimizer::enforce_sorting::test_with_lost_ordering_unbounded ... ok +test physical_optimizer::enforce_sorting::test_with_lost_ordering_bounded ... ok +test physical_optimizer::enforce_sorting::test_window_multi_path_sort2 ... ok +test physical_optimizer::enforce_sorting::union_with_mix_of_presorted_and_explicitly_resorted_inputs_with_repartition_sorts_false ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_0 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_1 ... ok +test physical_optimizer::enforce_sorting::union_with_mix_of_presorted_and_explicitly_resorted_inputs_with_repartition_sorts_true ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_11 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_10 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_12 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_13 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_14 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_15 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_17 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_16 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_19 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_18 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_2 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_21 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_20 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_22 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_23 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_24 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_26 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_25 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_27 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_28 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_29 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_3 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_31 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_30 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_33 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_32 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_34 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_36 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_35 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_37 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_39 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_4 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_38 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_40 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_41 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_43 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_44 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_46 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_45 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_42 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_47 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_48 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_49 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_50 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_5 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_52 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_54 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_51 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_55 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_53 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_57 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_58 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_56 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_6 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_60 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_59 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_61 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_62 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_63 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_8 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_9 ... ok +test physical_optimizer::enforce_sorting_monotonicity::test_window_partial_constant_and_set_monotonicity_7 ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_max_simple ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_min_all_nulls ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_min_expression_not_supported ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_min_max_different_columns ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_min_simple ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_min_max_same_column ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_not_created_for_single_mode ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_multiple_mixed_expressions ... ok +test physical_optimizer::filter_pushdown::test_aggregate_filter_pushdown ... ok +test physical_optimizer::filter_pushdown::test_filter_collapse ... ok +test physical_optimizer::filter_pushdown::test_filter_pushdown_through_union ... ok +test physical_optimizer::filter_pushdown::test_dynamic_filter_pushdown_through_hash_join_with_topk ... ok +test physical_optimizer::filter_pushdown::test_filter_with_projection ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_dynamic_filter_all_partitions_empty ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_dynamic_filter_pushdown ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_dynamic_filter_pushdown_is_used ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_dynamic_filter_pushdown_collect_left ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_dynamic_filter_with_nulls ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_dynamic_filter_pushdown_partitioned ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_hash_table_pushdown_collect_left ... ok +test physical_optimizer::filter_pushdown::test_aggregate_dynamic_filter_parquet_e2e ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_hash_table_pushdown_integer_keys ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_hash_table_pushdown_partitioned ... ok +test physical_optimizer::filter_pushdown::test_no_pushdown_filter_on_aggregate_result ... ok +test physical_optimizer::filter_pushdown::test_hashjoin_parent_filter_pushdown ... ok +test physical_optimizer::filter_pushdown::test_no_pushdown_grouping_sets_filter_on_missing_column ... ok +test physical_optimizer::filter_pushdown::test_push_down_through_transparent_nodes ... ok +test physical_optimizer::filter_pushdown::test_nested_hashjoin_dynamic_filter_pushdown ... ok +test physical_optimizer::filter_pushdown::test_pushdown_filter_on_non_first_grouping_column ... ok +test physical_optimizer::filter_pushdown::test_node_handles_child_pushdown_result ... ok +test physical_optimizer::filter_pushdown::test_pushdown_grouping_sets_filter_on_common_column ... ok +test physical_optimizer::filter_pushdown::test_pushdown_into_scan_with_config_options ... ok +test physical_optimizer::filter_pushdown::test_pushdown_into_scan ... ok +test physical_optimizer::filter_pushdown::test_pushdown_volatile_functions_not_allowed ... ok +test physical_optimizer::filter_pushdown::test_pushdown_through_aggregates_on_grouping_columns ... ok +test physical_optimizer::filter_pushdown::test_pushdown_with_empty_group_by ... ok +test physical_optimizer::filter_pushdown::test_pushdown_with_computed_grouping_key ... ok +test physical_optimizer::filter_pushdown::test_static_filter_pushdown_through_hash_join ... ok +test physical_optimizer::filter_pushdown::test_topk_dynamic_filter_pushdown ... ok +test physical_optimizer::filter_pushdown::test_topk_filter_passes_through_coalesce_partitions ... ok +test physical_optimizer::filter_pushdown::test_topk_dynamic_filter_pushdown_multi_column_sort ... ok +test physical_optimizer::join_selection::check_expr_supported ... ok +test physical_optimizer::join_selection::test_cases_without_collect_left_check ... ok +test physical_optimizer::join_selection::test_hash_join_swap_on_joins_with_projections::case_1_inner ... ok +test physical_optimizer::join_selection::test_hash_join_swap_on_joins_with_projections::case_2_left ... ok +test physical_optimizer::join_selection::test_hash_join_swap_on_joins_with_projections::case_3_right ... ok +test physical_optimizer::join_selection::test_hash_join_swap_on_joins_with_projections::case_4_full ... ok +test physical_optimizer::join_selection::test_hash_join_swap_on_joins_with_projections::case_5_left_anti ... ok +test physical_optimizer::join_selection::test_hash_join_swap_on_joins_with_projections::case_6_left_semi ... ok +test physical_optimizer::join_selection::test_hash_join_swap_on_joins_with_projections::case_7_right_anti ... ok +test physical_optimizer::join_selection::test_hash_join_swap_on_joins_with_projections::case_8_right_semi ... ok +test physical_optimizer::join_selection::test_join_no_swap ... ok +test physical_optimizer::filter_pushdown::test_topk_with_projection_transformation_on_dyn_filter ... ok +test physical_optimizer::join_selection::test_join_selection_collect_left ... ok +test physical_optimizer::join_selection::test_join_selection_partitioned ... ok +test physical_optimizer::join_selection::test_join_with_swap ... ok +test physical_optimizer::join_selection::test_join_with_swap_mark ... ok +test physical_optimizer::join_selection::test_join_with_swap_semi ... ok +test physical_optimizer::join_selection::test_join_with_swap_full ... ok +test physical_optimizer::join_selection::test_left_join_no_swap ... ok +test physical_optimizer::join_selection::test_nested_join_swap ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap::case_2_left ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap::case_1_inner ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap::case_4_full ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap_no_proj::case_1_left_semi ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap::case_3_right ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap_no_proj::case_2_left_anti ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap_no_proj::case_3_right_semi ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap_no_proj::case_4_right_anti ... ok +test physical_optimizer::join_selection::test_nl_join_with_swap_no_proj::case_5_right_mark ... ok +test physical_optimizer::join_selection::test_not_support_collect_left ... ok +test physical_optimizer::join_selection::test_not_supporting_swaps_possible_collect_left ... ok +test physical_optimizer::limit_pushdown::merges_global_limit_with_global_limit ... ok +test physical_optimizer::limit_pushdown::merges_global_limit_with_local_limit ... ok +test physical_optimizer::limit_pushdown::keeps_pushed_local_limit_exec_when_there_are_multiple_input_partitions ... ok +test physical_optimizer::limit_pushdown::merges_local_limit_with_global_limit ... ok +test physical_optimizer::limit_pushdown::merges_local_limit_with_local_limit ... ok +test physical_optimizer::limit_pushdown::pushes_global_limit_exec_through_projection_exec ... ok +test physical_optimizer::limit_pushdown::pushes_global_limit_into_multiple_fetch_plans ... ok +test physical_optimizer::limit_pushdown::transforms_streaming_table_exec_into_fetching_version_and_keeps_the_global_limit_when_skip_is_nonzero ... ok +test physical_optimizer::limit_pushdown::transforms_streaming_table_exec_into_fetching_version_when_skip_is_zero ... ok +test physical_optimizer::limited_distinct_aggregation::test_has_aggregate_expression ... ok +test physical_optimizer::limited_distinct_aggregation::test_has_filter ... ok +test physical_optimizer::limited_distinct_aggregation::test_distinct_cols_different_than_group_by_cols ... ok +test physical_optimizer::limited_distinct_aggregation::test_no_group_by ... ok +test physical_optimizer::limited_distinct_aggregation::test_has_order_by ... ok +test physical_optimizer::limited_distinct_aggregation::test_partial_final ... ok +test physical_optimizer::limited_distinct_aggregation::test_single_global ... ok +test physical_optimizer::limited_distinct_aggregation::test_single_local ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_coalesce_partitions ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_agg ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_cross_join ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_global_limit_partitions ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_local_limit ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_placeholder_rows ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_repartition ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_repartition_hash_partitioning ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_nested_loop_join ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_repartition_invalid_partition ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_repartition_zero_partitions ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_window_agg ... ok +test physical_optimizer::partition_statistics::test::test_statistic_by_partition_of_union ... ok +test physical_optimizer::partition_statistics::test::test_statistics_by_partition_of_filter ... ok +test physical_optimizer::partition_statistics::test::test_statistics_by_partition_of_data_source ... ok +test physical_optimizer::partition_statistics::test::test_statistics_by_partition_of_interleave ... ok +test physical_optimizer::partition_statistics::test::test_statistics_by_partition_of_projection ... ok +test physical_optimizer::projection_pushdown::test_coalesce_partitions_after_projection ... ok +test physical_optimizer::projection_pushdown::test_cooperative_exec_after_projection ... ok +test physical_optimizer::projection_pushdown::test_csv_after_projection ... ok +test physical_optimizer::projection_pushdown::test_filter_after_projection ... ok +test physical_optimizer::projection_pushdown::test_hash_join_after_projection ... ok +test physical_optimizer::projection_pushdown::test_join_after_projection ... ok +test physical_optimizer::partition_statistics::test::test_statistics_by_partition_of_sort ... ok +test physical_optimizer::projection_pushdown::test_join_after_required_projection ... ok +test physical_optimizer::projection_pushdown::test_memory_after_projection ... ok +test physical_optimizer::projection_pushdown::test_nested_loop_join_after_projection ... ok +test physical_optimizer::projection_pushdown::test_output_req_after_projection ... ok +test physical_optimizer::projection_pushdown::test_partition_col_projection_pushdown ... ok +test physical_optimizer::projection_pushdown::test_partition_col_projection_pushdown_expr ... ok +test physical_optimizer::projection_pushdown::test_projection_after_projection ... ok +test physical_optimizer::projection_pushdown::test_sort_after_projection ... ok +test physical_optimizer::projection_pushdown::test_repartition_after_projection ... ok +test physical_optimizer::projection_pushdown::test_sort_preserving_after_projection ... ok +test physical_optimizer::projection_pushdown::test_streaming_table_after_projection ... ok +test physical_optimizer::projection_pushdown::test_update_matching_exprs ... ok +test physical_optimizer::projection_pushdown::test_union_after_projection ... ok +test physical_optimizer::pushdown_sort::test_complex_plan_with_multiple_operators ... ok +test physical_optimizer::projection_pushdown::test_update_projected_exprs ... ok +test physical_optimizer::pushdown_sort::test_multiple_sorts_different_columns ... ok +test physical_optimizer::pushdown_sort::test_nested_sorts ... ok +test physical_optimizer::pushdown_sort::test_no_prefix_match_longer_than_source ... ok +test physical_optimizer::pushdown_sort::test_no_pushdown_for_non_reverse_sort ... ok +test physical_optimizer::pushdown_sort::test_no_prefix_match_wrong_direction ... ok +test physical_optimizer::pushdown_sort::test_no_pushdown_for_unordered_source ... ok +test physical_optimizer::pushdown_sort::test_non_sort_plans_unchanged ... ok +test physical_optimizer::pushdown_sort::test_optimizer_properties ... ok +test physical_optimizer::pushdown_sort::test_no_sort_pushdown_through_computed_projection ... ok +test physical_optimizer::pushdown_sort::test_prefix_match_single_column ... ok +test physical_optimizer::pushdown_sort::test_prefix_match_with_limit ... ok +test physical_optimizer::pushdown_sort::test_pushdown_through_blocking_node ... ok +test physical_optimizer::pushdown_sort::test_prefix_match_through_transparent_nodes ... ok +test physical_optimizer::pushdown_sort::test_sort_multiple_columns_phase1 ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_basic_phase1 ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_disabled ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_projection_reordered_columns ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_projection_subset_of_columns ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_through_projection ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_projection_with_limit ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_through_projection_with_alias ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_with_test_scan_arbitrary_ordering ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_with_test_scan_basic ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_through_simple_projection ... ok +test physical_optimizer::pushdown_sort::test_sort_pushdown_with_test_scan_multi_column ... ok +test physical_optimizer::pushdown_sort::test_sort_through_coalesce_partitions ... ok +test physical_optimizer::pushdown_sort::test_sort_through_repartition ... ok +test physical_optimizer::pushdown_sort::test_sort_with_limit_phase1 ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_not_replace_with_different_orderings::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_not_replace_with_different_orderings::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_not_replace_with_different_orderings::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_not_replacing_when_no_need_to_preserve_sorting::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_not_replace_with_different_orderings::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_not_replacing_when_no_need_to_preserve_sorting::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_not_replacing_when_no_need_to_preserve_sorting::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_plan_with_order_breaking_variants_preserves_fetch ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_plan_with_order_preserving_variants_preserves_fetch ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_not_replacing_when_no_need_to_preserve_sorting::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_1::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_1::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_1::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_1::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_2::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_2::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_2::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_with_extra_steps::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_with_extra_steps::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_2::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_with_extra_steps::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_with_extra_steps_2::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_with_extra_steps_2::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_with_extra_steps::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_with_extra_steps_2::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_inter_children_change_only::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_inter_children_change_only::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_replace_multiple_input_repartition_with_extra_steps_2::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_inter_children_change_only::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_lost_and_kept_ordering::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_lost_and_kept_ordering::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_inter_children_change_only::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_lost_and_kept_ordering::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_lost_ordering::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_lost_ordering::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_lost_and_kept_ordering::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_lost_ordering::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_multiple_child_trees::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_lost_ordering::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_multiple_child_trees::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_multiple_child_trees::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_multiple_replaceable_repartitions::boundedness_1_Boundedness__Unbounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_multiple_child_trees::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_multiple_replaceable_repartitions::boundedness_1_Boundedness__Unbounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_multiple_replaceable_repartitions::boundedness_2_Boundedness__Bounded::sort_pref_1_SortPreference__PreserveOrder ... ok +test physical_optimizer::replace_with_order_preserving_variants::test_with_multiple_replaceable_repartitions::boundedness_2_Boundedness__Bounded::sort_pref_2_SortPreference__MaximizeParallelism ... ok +test physical_optimizer::sanity_checker::test_analyzer ... ok +test physical_optimizer::sanity_checker::test_bounded_window_agg_no_sort_requirement ... ok +test physical_optimizer::sanity_checker::test_bounded_window_agg_sort_requirement ... ok +test physical_optimizer::sanity_checker::test_global_limit_multi_partition ... ok +test physical_optimizer::sanity_checker::test_global_limit_single_partition ... ok +test physical_optimizer::sanity_checker::test_aggregate ... ok +test physical_optimizer::sanity_checker::test_hash_full_outer_join_swap ... ok +test physical_optimizer::sanity_checker::test_hash_cross_join ... ok +test physical_optimizer::sanity_checker::test_hash_left_join_swap ... ok +test physical_optimizer::sanity_checker::test_hash_inner_join_swap ... ok +test physical_optimizer::sanity_checker::test_local_limit ... ok +test physical_optimizer::sanity_checker::test_sort_merge_join_dist_missing ... ok +test physical_optimizer::sanity_checker::test_sort_merge_join_order_missing ... ok +test physical_optimizer::sanity_checker::test_sort_merge_join_satisfied ... ok +test physical_optimizer::sanity_checker::test_union_with_sorts_and_constants ... ok +test physical_optimizer::sanity_checker::test_hash_right_join_swap ... ok +test physical_optimizer::sanity_checker::test_window_agg_hash_partition ... ok +test physical_optimizer::window_optimize::test::test_window_constant_aggregate ... ok +test physical_optimizer::sanity_checker::test_window_agg_single_partition ... ok +test sql::aggregates::basic::count_aggregated ... ok +test sql::aggregates::basic::count_aggregated_cube ... ok +test sql::aggregates::basic::count_distinct_dictionary_all_null_values ... ok +test sql::aggregates::basic::count_distinct_dictionary_mixed_values ... ok +test sql::aggregates::basic::count_distinct_integers_aggregated_single_partition ... ok +test sql::aggregates::basic::count_distinct_integers_aggregated_multiple_partitions ... ok +test memory_limit::test_spill_file_compressed_with_zstd ... ok +test sql::aggregates::basic::count_partitioned ... ok +test sql::aggregates::basic::csv_query_array_agg_distinct ... ok +test sql::aggregates::dict_nulls::test_count_distinct_with_fuzz_table_dict_nulls ... ok +test physical_optimizer::filter_pushdown::test_topk_dynamic_filter_pushdown_integration ... ok +test sql::aggregates::dict_nulls::test_first_last_val_null_handling ... ok +test sql::aggregates::basic::test_accumulator_row_accumulator ... ok +test sql::aggregates::dict_nulls::test_aggregates_null_handling_comprehensive ... ok +test sql::aggregates::dict_nulls::test_first_last_value_order_by_null_handling ... ok +test sql::aggregates::dict_nulls::test_first_last_value_group_by_dict_nulls ... ok +test sql::create_drop::create_custom_table ... ok +test sql::create_drop::create_drop_table ... ok +test sql::create_drop::create_external_table_with_ddl ... ok +test sql::aggregates::dict_nulls::test_max_with_fuzz_table_dict_nulls ... ok +test sql::aggregates::dict_nulls::test_min_timestamp_with_fuzz_table_dict_nulls ... ok +test sql::aggregates::dict_nulls::test_median_distinct_with_fuzz_table_dict_nulls ... ok +test sql::explain_analyze::csv_explain_analyze ... ok +test sql::explain_analyze::csv_explain_analyze_order_by ... ok +test sql::explain_analyze::csv_explain_analyze_with_statistics ... ok +test sql::explain_analyze::csv_explain_inlist_verbose ... ok +test sql::explain_analyze::csv_explain_verbose ... ok +test sql::explain_analyze::csv_explain_plans ... ok +test sql::explain_analyze::csv_explain_verbose_plans ... ok +test sql::explain_analyze::explain_analyze_hash_join ... ok +test sql::explain_analyze::csv_explain_analyze_verbose ... ok +test sql::explain_analyze::explain_analyze_baseline_metrics ... ok +test sql::explain_analyze::explain_analyze_runs_optimizers::count_expr_1______ ... ok +test sql::explain_analyze::explain_analyze_parquet_pruning_metrics ... ok +test sql::explain_analyze::explain_analyze_level ... ok +test sql::explain_analyze::explain_analyze_level_datasource_parquet ... ok +test sql::explain_analyze::explain_logical_plan_only ... ok +test sql::explain_analyze::explain_analyze_runs_optimizers::count_expr_2___1__ ... ok +test sql::explain_analyze::explain_physical_plan_only ... ok +test sql::explain_analyze::parquet_explain_analyze ... ok +test sql::explain_analyze::parquet_recursive_projection_pushdown ... ok +test sql::explain_analyze::parquet_explain_analyze_verbose ... ok +test sql::explain_analyze::test_physical_plan_display_indent ... ok +test sql::explain_analyze::test_physical_plan_display_indent_multi_children ... ok +test sql::joins::join_change_in_planner ... ok +test sql::joins::join_change_in_planner_without_sort ... ok +test sql::joins::join_change_in_planner_without_sort_not_allowed ... ok +test sql::joins::join_no_order_on_filter ... ok +test sql::explain_analyze::nested_loop_join_selectivity ... ok +test sql::nyc ... ok +test sql::joins::unparse_cross_join ... ok +test sql::joins::join_using_uppercase_column ... ok +test sql::path_partition::csv_filter_with_file_nonstring_col ... ok +test sql::path_partition::csv_filter_with_file_col ... ok +test sql::path_partition::parquet_multiple_nonstring_partitions ... ok +test sql::path_partition::csv_projection_on_partition ... ok +test sql::path_partition::parquet_multiple_partitions ... ok +test sql::path_partition::parquet_overlapping_columns ... ok +test sql::runtime_config::test_invalid_memory_limit ... ok +test sql::path_partition::csv_grouping_by_partition ... ok +test sql::path_partition::parquet_statistics ... ok +test sql::runtime_config::test_list_files_cache_ttl ... ok +test sql::runtime_config::test_list_files_cache_limit ... ok +test sql::path_partition::parquet_distinct_partition_col ... ok +test sql::runtime_config::test_memory_limit_enforcement ... ok +test sql::runtime_config::test_multiple_configs ... ok +test sql::runtime_config::test_test_metadata_cache_limit ... ok +test sql::runtime_config::test_unknown_runtime_config ... ok +test sql::runtime_config::test_max_temp_directory_size_enforcement ... ok +test sql::select::prepared_statement_type_coercion ... ok +test sql::select::test_list_query_parameters ... ok +test sql::select::test_named_parameter_not_bound ... ok +test sql::select::test_parameter_invalid_types ... ok +test sql::select::test_parameter_type_coercion ... ok +test sql::select::test_named_query_parameters ... ok +test sql::select::test_positional_parameter_not_bound ... ok +test sql::runtime_config::test_no_spill_with_adequate_memory ... ok +test sql::select::test_query_parameters_with_metadata ... ok +test sql::select::test_select_cast_date_literal_to_timestamp_overflow ... ok +test sql::select::test_version_function ... ok +test sql::sql_api::ddl_can_not_be_planned_by_session_state ... ok +test sql::select::test_select_no_projection ... ok +test sql::sql_api::disable_prepare_and_execute_statement ... ok +test sql::sql_api::dml_output_schema ... ok +test sql::sql_api::empty_statement_returns_error ... ok +test sql::sql_api::multiple_statements_returns_error ... ok +test sql::sql_api::test_window_function ... ok +test sql::select::test_prepare_statement ... ok +test sql::sql_api::unsupported_copy_returns_error ... ok +test sql::sql_api::unsupported_ddl_returns_error ... ok +test sql::sql_api::unsupported_statement_returns_error ... ok +test sql::sql_api::unsupported_dml_returns_error ... ok +test tracing::test_tracer_injection ... ok +test fifo::unix_test::test_sql_insert_into_fifo ... ok +test fifo::unix_test::unbounded_file_with_swapped_join ... ok +test memory_limit::test_spill_file_compressed_with_lz4_frame ... ok +test fifo::unix_test::unbounded_file_with_symmetric_join ... ok +test dataframe::describe::describe ... ok +test sql::unparser::test_clickbench_unparser_roundtrip ... ok +test sql::unparser::test_tpch_unparser_roundtrip ... ok +test memory_limit::test_in_mem_buffer_almost_full ... ok +test memory_limit::test_external_sort_zero_merge_reservation ... ok +test memory_limit::test_stringview_external_sort ... ok +test sql::runtime_config::test_memory_limit_with_spill ... ok + +test result: ok. 876 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.00s + + Running tests/fuzz.rs (target/debug/deps/fuzz-0e641ff3d969bfdc) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/parquet_integration.rs (target/debug/deps/parquet_integration-9753ebfc7a6f85fa) + +running 193 tests +test parquet::external_access_plan::bad_row_groups ... ok +test parquet::external_access_plan::bad_selection ... ok +test parquet::external_access_plan::none ... ok +test parquet::external_access_plan::scan_all ... ok +test parquet::external_access_plan::skip_all ... ok +test parquet::external_access_plan::skip_one_row_group ... ok +test parquet::external_access_plan::selection_scan ... ok +test parquet::external_access_plan::skip_scan ... ok +test parquet::external_access_plan::plan_and_filter ... ok +test parquet::file_statistics::load_table_stats_with_session_level_cache ... ok +test parquet::file_statistics::check_stats_precision_with_filter_pushdown ... ok +test parquet::external_access_plan::two_selections ... ok +test parquet::file_statistics::list_files_with_session_level_cache ... ok +test parquet::filter_pushdown::predicate_cache_pushdown_default ... ok +test parquet::expr_adapter::test_physical_expr_adapter_with_non_null_defaults ... ok +test parquet::filter_pushdown::predicate_cache_default ... ok +test parquet::filter_pushdown::predicate_cache_pushdown_disable ... ok +test parquet::expr_adapter::test_custom_schema_adapter_and_custom_expression_adapter ... ok +test parquet::expr_adapter::test_physical_expr_adapter_factory_reuse_across_tables ... ok +test parquet::filter_pushdown::predicate_cache_pushdown_default_selections_only ... ok +test parquet::filter_pushdown::predicate_cache_stats_issue_19561 ... ok +test parquet::ordering::test_create_table_with_order_writes_sorting_columns ... ok +test parquet::encryption::round_trip_parquet_with_encryption_factory ... ok +test parquet::page_pruning::prune_date64 ... ok +test parquet::page_pruning::prune_date32 ... ok +test parquet::page_pruning::prune_f64_complex_expr ... ok +test parquet::page_pruning::prune_f64_complex_expr_subtract ... ok +test parquet::page_pruning::prune_f64_scalar_fun ... ok +test parquet::page_pruning::prune_f64_scalar_fun_and_gt ... ok +test parquet::page_pruning::prune_f64_lt ... ok +test parquet::page_pruning::prune_int16_complex_expr ... ok +test parquet::page_pruning::prune_int16_complex_expr_subtract ... ok +test parquet::page_pruning::prune_decimal_eq ... ok +test parquet::page_pruning::prune_decimal_lt ... ok +test parquet::page_pruning::prune_int16_eq ... ok +test parquet::page_pruning::prune_decimal_in_list ... ok +test parquet::page_pruning::prune_int16_eq_in_list ... ok +test parquet::page_pruning::prune_int16_scalar_fun ... ok +test parquet::page_pruning::prune_int16_eq_in_list_negated ... ok +test parquet::page_pruning::prune_int16_scalar_fun_and_eq ... ok +test parquet::page_pruning::prune_int32_complex_expr ... ok +test parquet::page_pruning::prune_int32_eq_in_list ... ok +test parquet::page_pruning::prune_int32_complex_expr_subtract ... ok +test parquet::page_pruning::prune_int32_eq ... ok +test parquet::page_pruning::prune_int16_gt ... ok +test parquet::page_pruning::prune_int16_lt ... ok +test parquet::page_pruning::prune_int32_eq_in_list_negated ... ok +test parquet::page_pruning::prune_int64_complex_expr_subtract ... ok +test parquet::page_pruning::prune_int32_scalar_fun ... ok +test parquet::page_pruning::prune_int64_complex_expr ... ok +test parquet::page_pruning::prune_int32_scalar_fun_and_eq ... ok +test parquet::page_pruning::prune_int32_gt ... ok +test parquet::page_pruning::prune_int32_lt ... ok +test parquet::page_pruning::prune_int64_eq_in_list ... ok +test parquet::page_pruning::prune_int64_eq_in_list_negated ... ok +test parquet::page_pruning::prune_int64_eq ... ok +test parquet::page_pruning::prune_int64_scalar_fun ... ok +test parquet::encryption::round_trip_encryption ... ok +test parquet::page_pruning::prune_int8_complex_expr_subtract ... ok +test parquet::page_pruning::prune_int64_gt ... ok +test parquet::page_pruning::prune_int64_scalar_fun_and_eq ... ok +test parquet::page_pruning::prune_int8_complex_expr ... ok +test parquet::page_pruning::prune_int8_eq ... ok +test parquet::page_pruning::prune_int64_lt ... ok +test parquet::page_pruning::prune_int8_eq_in_list ... ok +test parquet::page_pruning::prune_int8_eq_in_list_negated ... ok +test parquet::page_pruning::prune_timestamps_micros ... ok +test parquet::page_pruning::prune_int8_scalar_fun ... ok +test parquet::page_pruning::prune_int8_scalar_fun_and_eq ... ok +test parquet::page_pruning::prune_int8_gt ... ok +test parquet::page_pruning::prune_int8_lt ... ok +test parquet::page_pruning::prune_uint16_eq ... ok +test parquet::page_pruning::prune_timestamps_nanos ... ok +test parquet::page_pruning::prune_uint16_complex_expr ... ok +test parquet::page_pruning::prune_timestamps_seconds ... ok +test parquet::page_pruning::prune_timestamps_millis ... ok +test parquet::page_pruning::prune_uint16_eq_in_list ... ok +test parquet::page_pruning::prune_uint16_eq_in_list_negated ... ok +test parquet::page_pruning::prune_uint16_lt ... ok +test parquet::page_pruning::prune_uint16_gt ... ok +test parquet::page_pruning::prune_uint16_scalar_fun ... ok +test parquet::page_pruning::prune_uint32_complex_expr ... ok +test parquet::page_pruning::prune_uint16_scalar_fun_and_eq ... ok +test parquet::page_pruning::prune_uint32_eq_in_list ... ok +test parquet::page_pruning::prune_uint32_eq ... ok +test parquet::page_pruning::prune_uint32_gt ... ok +test parquet::page_pruning::prune_uint32_scalar_fun ... ok +test parquet::page_pruning::prune_uint32_eq_in_list_negated ... ok +test parquet::page_pruning::prune_uint32_lt ... ok +test parquet::page_pruning::prune_uint32_scalar_fun_and_eq ... ok +test parquet::page_pruning::prune_uint64_complex_expr ... ok +test parquet::page_pruning::prune_uint64_eq ... ok +test parquet::page_pruning::prune_uint64_eq_in_list_negated ... ok +test parquet::page_pruning::prune_uint64_lt ... ok +test parquet::page_pruning::prune_uint64_eq_in_list ... ok +test parquet::page_pruning::prune_uint64_gt ... ok +test parquet::page_pruning::prune_uint64_scalar_fun ... ok +test parquet::page_pruning::prune_uint64_scalar_fun_and_eq ... ok +test parquet::page_pruning::prune_uint8_eq_in_list ... ok +test parquet::page_pruning::prune_uint8_eq ... ok +test parquet::page_pruning::prune_uint8_complex_expr ... ok +test parquet::page_pruning::prune_uint8_eq_in_list_negated ... ok +test parquet::page_pruning::prune_uint8_gt ... ok +test parquet::page_pruning::prune_uint8_lt ... ok +test parquet::page_pruning::test_parquet_opener_without_page_index ... ok +test parquet::page_pruning::prune_uint8_scalar_fun ... ok +test parquet::page_pruning::prune_uint8_scalar_fun_and_eq ... ok +test parquet::custom_reader::route_data_access_ops_to_parquet_file_reader_factory ... ok +test parquet::page_pruning::without_pushdown_filter ... ok +test parquet::row_group_pruning::prune_date32 ... ok +test parquet::row_group_pruning::prune_date64 ... ok +test parquet::page_pruning::test_pages_with_null_values ... ok +test parquet::row_group_pruning::prune_binary_lt ... ok +test parquet::row_group_pruning::prune_f64_complex_expr ... ok +test parquet::row_group_pruning::prune_f64_complex_expr_subtract ... ok +test parquet::row_group_pruning::prune_decimal_lt ... ok +test parquet::row_group_pruning::prune_f64_scalar_fun ... ok +test parquet::row_group_pruning::prune_f64_lt ... ok +test parquet::row_group_pruning::prune_f64_scalar_fun_and_gt ... ok +test parquet::row_group_pruning::prune_binary_eq_match ... ok +test parquet::row_group_pruning::prune_disabled ... ok +test parquet::row_group_pruning::prune_fixedsizebinary_eq_no_match ... ok +test parquet::row_group_pruning::prune_binary_eq_no_match ... ok +test parquet::row_group_pruning::prune_fixedsizebinary_lt ... ok +test parquet::row_group_pruning::prune_int32_complex_expr ... ok +test parquet::row_group_pruning::prune_binary_neq ... ok +test parquet::row_group_pruning::prune_int32_complex_expr_subtract ... ok +test parquet::row_group_pruning::prune_int32_eq_in_list_2 ... ok +test parquet::row_group_pruning::prune_int32_eq ... ok +test parquet::row_group_pruning::prune_int32_eq_in_list ... ok +test parquet::page_pruning::page_index_filter_one_col ... ok +test parquet::row_group_pruning::prune_int32_eq_large_in_list ... ok +test parquet::row_group_pruning::prune_int32_scalar_fun ... ok +test parquet::row_group_pruning::prune_int64_complex_expr ... ok +test parquet::row_group_pruning::prune_int32_lt ... ok +test parquet::row_group_pruning::prune_fixedsizebinary_neq ... ok +test parquet::row_group_pruning::prune_int32_scalar_fun_and_eq ... ok +test parquet::row_group_pruning::prune_int64_complex_expr_subtract ... ok +test parquet::row_group_pruning::prune_int64_eq_in_list_2 ... ok +test parquet::page_pruning::page_index_filter_multi_col ... ok +test parquet::filter_pushdown::single_file_small_data_pages ... ok +test parquet::row_group_pruning::prune_int64_eq_in_list ... ok +test parquet::row_group_pruning::prune_int64_scalar_fun ... ok +test parquet::row_group_pruning::prune_int64_eq ... ok +test parquet::row_group_pruning::prune_fixedsizebinary_eq_match ... ok +test parquet::row_group_pruning::prune_int32_eq_in_list_negated ... ok +test parquet::row_group_pruning::prune_int64_eq_in_list_negated ... ok +test parquet::row_group_pruning::prune_int64_lt ... ok +test parquet::row_group_pruning::prune_int64_scalar_fun_and_eq ... ok +test parquet::row_group_pruning::prune_timestamps_micros ... ok +test parquet::row_group_pruning::prune_string_lt ... ok +test parquet::row_group_pruning::prune_timestamps_millis ... ok +test parquet::row_group_pruning::prune_string_neq ... ok +test parquet::row_group_pruning::prune_timestamps_nanos ... ok +test parquet::row_group_pruning::prune_uint32_complex_expr ... ok +test parquet::row_group_pruning::prune_timestamps_seconds ... ok +test parquet::row_group_pruning::prune_uint32_eq_in_list_2 ... ok +test parquet::row_group_pruning::prune_decimal_eq ... ok +test parquet::row_group_pruning::prune_string_eq_match ... ok +test parquet::row_group_pruning::prune_uint32_eq ... ok +test parquet::row_group_pruning::prune_uint32_eq_in_list ... ok +test parquet::row_group_pruning::prune_uint32_eq_large_in_list ... ok +test parquet::row_group_pruning::prune_uint32_lt ... ok +test parquet::row_group_pruning::prune_uint32_scalar_fun ... ok +test parquet::row_group_pruning::prune_uint64_complex_expr ... ok +test parquet::row_group_pruning::prune_uint64_eq_in_list_2 ... ok +test parquet::row_group_pruning::prune_uint32_scalar_fun_and_eq ... ok +test parquet::row_group_pruning::prune_uint64_lt ... ok +test parquet::row_group_pruning::prune_uint64_eq ... ok +test parquet::row_group_pruning::prune_string_eq_no_match ... ok +test parquet::row_group_pruning::prune_uint64_scalar_fun ... ok +test parquet::row_group_pruning::prune_uint64_scalar_fun_and_eq ... ok +test parquet::row_group_pruning::prune_uint64_eq_in_list ... ok +test parquet::row_group_pruning::prune_decimal_in_list ... ok +test parquet::row_group_pruning::test_limit_pruning_basic ... ok +test parquet::row_group_pruning::test_bloom_filter_decimal_dict ... ok +test parquet::row_group_pruning::prune_periods_in_column_names ... ok +test parquet::row_group_pruning::prune_uint32_eq_in_list_negated ... ok +test parquet::row_group_pruning::test_bloom_filter_unsigned_integer_dict ... ok +test parquet::schema::schema_merge_can_preserve_metadata ... ok +test parquet::schema_coercion::multi_parquet_coercion ... ok +test parquet::schema::schema_merge_ignores_metadata_by_default ... ok +test parquet::schema_coercion::multi_parquet_coercion_projection ... ok +test parquet::row_group_pruning::prune_uint64_eq_in_list_negated ... ok +test parquet::row_group_pruning::test_limit_pruning_multiple_fully_matched ... ok +test parquet::row_group_pruning::test_limit_pruning_exceeds_fully_matched ... ok +test parquet::row_group_pruning::test_limit_pruning_complex_filter ... ok +test parquet::row_group_pruning::test_bloom_filter_binary_dict ... ok +test parquet::row_group_pruning::test_row_group_with_null_values ... ok +test parquet::row_group_pruning::test_bloom_filter_integer_dict ... ok +test parquet::row_group_pruning::test_limit_pruning_no_fully_matched ... ok +test parquet::row_group_pruning::test_bloom_filter_utf8_dict ... ok +test parquet::filter_pushdown::single_file ... ok + +test result: ok. 193 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.51s + + Running tests/set_comparison.rs (target/debug/deps/set_comparison-18a4109971e923c8) + +running 6 tests +test set_comparison_type_mismatch ... ok +test set_comparison_null_semantics_all ... ok +test set_comparison_all_empty ... ok +test set_comparison_any ... ok +test set_comparison_any_aggregate_subquery ... ok +test set_comparison_multiple_operators ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s + + Running tests/tpcds_planning.rs (target/debug/deps/tpcds_planning-01847f037536f936) + +running 198 tests +test tpcds_logical_q12 ... ok +test tpcds_logical_q16 ... ok +test tpcds_logical_q15 ... ok +test tpcds_logical_q19 ... ok +test tpcds_logical_q2 ... ok +test tpcds_logical_q20 ... ok +test tpcds_logical_q18 ... ok +test tpcds_logical_q1 ... ok +test tpcds_logical_q13 ... ok +test tpcds_logical_q22 ... ok +test tpcds_logical_q17 ... ok +test tpcds_logical_q21 ... ok +test tpcds_logical_q3 ... ok +test tpcds_logical_q10 ... ok +test tpcds_logical_q26 ... ok +test tpcds_logical_q27 ... ok +test tpcds_logical_q32 ... ok +test tpcds_logical_q34 ... ok +test tpcds_logical_q25 ... ok +test tpcds_logical_q30 ... ok +test tpcds_logical_q28 ... ok +test tpcds_logical_q29 ... ok +test tpcds_logical_q36 ... ok +test tpcds_logical_q37 ... ok +test tpcds_logical_q33 ... ok +test tpcds_logical_q38 ... ok +test tpcds_logical_q42 ... ok +test tpcds_logical_q35 ... ok +test tpcds_logical_q31 ... ok +test tpcds_logical_q40 ... ok +test tpcds_logical_q43 ... ok +test tpcds_logical_q45 ... ok +test tpcds_logical_q44 ... ok +test tpcds_logical_q41 ... ok +test tpcds_logical_q11 ... ok +test tpcds_logical_q48 ... ok +test tpcds_logical_q46 ... ok +test tpcds_logical_q52 ... ok +test tpcds_logical_q24 ... ok +test tpcds_logical_q53 ... ok +test tpcds_logical_q39 ... ok +test tpcds_logical_q51 ... ok +test tpcds_logical_q50 ... ok +test tpcds_logical_q55 ... ok +test tpcds_logical_q47 ... ok +test tpcds_logical_q5 ... ok +test tpcds_logical_q6 ... ok +test tpcds_logical_q54 ... ok +test tpcds_logical_q57 ... ok +test tpcds_logical_q58 ... ok +test tpcds_logical_q49 ... ok +test tpcds_logical_q62 ... ok +test tpcds_logical_q56 ... ok +test tpcds_logical_q63 ... ok +test tpcds_logical_q65 ... ok +test tpcds_logical_q59 ... ok +test tpcds_logical_q61 ... ok +test tpcds_logical_q60 ... ok +test tpcds_logical_q67 ... ok +test tpcds_logical_q68 ... ok +test tpcds_logical_q7 ... ok +test tpcds_logical_q70 ... ok +test tpcds_logical_q71 ... ok +test tpcds_logical_q73 ... ok +test tpcds_logical_q76 ... ok +test tpcds_logical_q69 ... ok +test tpcds_logical_q79 ... ok +test tpcds_logical_q72 ... ok +test tpcds_logical_q8 ... ok +test tpcds_logical_q81 ... ok +test tpcds_logical_q78 ... ok +test tpcds_logical_q74 ... ok +test tpcds_logical_q82 ... ok +test tpcds_logical_q23 ... ok +test tpcds_logical_q77 ... ok +test tpcds_logical_q84 ... ok +test tpcds_logical_q86 ... ok +test tpcds_logical_q87 ... ok +test tpcds_logical_q89 ... ok +test tpcds_logical_q75 ... ok +test tpcds_logical_q90 ... ok +test tpcds_logical_q83 ... ok +test tpcds_logical_q9 ... ok +test tpcds_logical_q93 ... ok +test tpcds_logical_q92 ... ok +test tpcds_logical_q85 ... ok +test tpcds_logical_q80 ... ok +test tpcds_logical_q98 ... ok +test tpcds_logical_q91 ... ok +test tpcds_logical_q97 ... ok +test tpcds_logical_q88 ... ok +test tpcds_logical_q96 ... ok +test tpcds_logical_q94 ... ok +test tpcds_logical_q95 ... ok +test tpcds_logical_q99 ... ok +test tpcds_physical_q1 ... ok +test tpcds_physical_q15 ... ok +test tpcds_physical_q12 ... ok +test tpcds_physical_q16 ... ok +test tpcds_physical_q13 ... ok +test tpcds_logical_q4 ... ok +test tpcds_physical_q10 ... ok +test tpcds_logical_q66 ... ok +test tpcds_physical_q22 ... ok +test tpcds_physical_q19 ... ok +test tpcds_physical_q20 ... ok +test tpcds_physical_q17 ... ok +test tpcds_logical_q64 ... ok +test tpcds_physical_q21 ... ok +test tpcds_physical_q18 ... ok +test tpcds_physical_q2 ... ok +test tpcds_logical_q14 ... ok +test tpcds_physical_q26 ... ok +test tpcds_physical_q3 ... ok +test tpcds_physical_q27 ... ok +test tpcds_physical_q28 ... ok +test tpcds_physical_q25 ... ok +test tpcds_physical_q32 ... ok +test tpcds_physical_q34 ... ok +test tpcds_physical_q29 ... ok +test tpcds_physical_q37 ... ok +test tpcds_physical_q30 ... ok +test tpcds_physical_q36 ... ok +test tpcds_physical_q38 ... ok +test tpcds_physical_q31 ... ok +test tpcds_physical_q42 ... ok +test tpcds_physical_q40 ... ok +test tpcds_physical_q33 ... ok +test tpcds_physical_q43 ... ok +test tpcds_physical_q35 ... ok +test tpcds_physical_q41 ... ok +test tpcds_physical_q46 ... ok +test tpcds_physical_q45 ... ok +test tpcds_physical_q44 ... ok +test tpcds_physical_q48 ... ok +test tpcds_physical_q11 ... ok +test tpcds_physical_q52 ... ok +test tpcds_physical_q53 ... ok +test tpcds_physical_q51 ... ok +test tpcds_physical_q24 ... ok +test tpcds_physical_q50 ... ok +test tpcds_physical_q39 ... ok +test tpcds_physical_q55 ... ok +test tpcds_physical_q5 ... ok +test tpcds_physical_q23 ... ok +test tpcds_physical_q49 ... ok +test tpcds_physical_q6 ... ok +test tpcds_physical_q54 ... ok +test tpcds_physical_q56 ... ok +test tpcds_physical_q62 ... ok +test tpcds_physical_q58 ... ok +test tpcds_physical_q63 ... ok +test tpcds_physical_q59 ... ok +test tpcds_physical_q60 ... ok +test tpcds_physical_q47 ... ok +test tpcds_physical_q61 ... ok +test tpcds_physical_q65 ... ok +test tpcds_physical_q7 ... ok +test tpcds_physical_q68 ... ok +test tpcds_physical_q67 ... ok +test tpcds_physical_q73 ... ok +test tpcds_physical_q71 ... ok +test tpcds_physical_q69 ... ok +test tpcds_physical_q76 ... ok +test tpcds_physical_q70 ... ok +test tpcds_physical_q57 ... ok +test tpcds_physical_q79 ... ok +test tpcds_physical_q72 ... ok +test tpcds_physical_q8 ... ok +test tpcds_physical_q77 ... ok +test tpcds_physical_q82 ... ok +test tpcds_physical_q81 ... ok +test tpcds_physical_q78 ... ok +test tpcds_physical_q84 ... ok +test tpcds_physical_q86 ... ok +test tpcds_physical_q83 ... ok +test tpcds_physical_q87 ... ok +test tpcds_physical_q74 ... ok +test tpcds_physical_q85 ... ok +test tpcds_physical_q80 ... ok +test tpcds_physical_q90 ... ok +test tpcds_physical_q93 ... ok +test tpcds_physical_q92 ... ok +test tpcds_physical_q75 ... ok +test tpcds_physical_q91 ... ok +test tpcds_physical_q89 ... ok +test tpcds_physical_q9 ... ok +test tpcds_physical_q96 ... ok +test tpcds_physical_q98 ... ok +test tpcds_physical_q97 ... ok +test tpcds_physical_q88 ... ok +test tpcds_physical_q94 ... ok +test tpcds_physical_q14 ... ok +test tpcds_physical_q99 ... ok +test tpcds_physical_q95 ... ok +test tpcds_physical_q66 ... ok +test tpcds_physical_q4 ... ok +test tpcds_physical_q64 ... ok + +test result: ok. 198 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.17s + + Running tests/user_defined_integration.rs (target/debug/deps/user_defined_integration-87a8e3ffb2b52885) + +running 79 tests +test user_defined::insert_operation::insert_operation_is_passed_correctly_to_table_provider ... ok +test user_defined::relation_planner::tests::error_handling_premium_feature_blocking ... ok +test user_defined::expr_planner::test_question_filter ... ok +test user_defined::expr_planner::test_question_select ... ok +test user_defined::expr_planner::test_custom_operators_arrow ... ok +test user_defined::expr_planner::test_custom_operators_long_arrow ... ok +test user_defined::relation_planner::tests::catalog_fallback_when_no_planner ... ok +test user_defined::relation_planner::tests::virtual_table_basic_select ... ok +test user_defined::relation_planner::tests::lifo_precedence_last_planner_wins ... ok +test user_defined::relation_planner::tests::delegation_pass_through_to_catalog ... ok +test user_defined::user_defined_aggregates::case_sensitive_identifiers_user_defined_aggregates ... ok +test user_defined::relation_planner::tests::recursive_planning_sampling_join ... ok +test user_defined::user_defined_aggregates::deregister_udaf ... ok +test user_defined::relation_planner::tests::multiple_planners_virtual_tables ... ok +test user_defined::user_defined_aggregates::simple_udaf ... ok +test user_defined::user_defined_aggregates::test_parameterized_aggregate_udf ... ok +test user_defined::user_defined_aggregates::test_metadata_based_aggregate ... ok +test user_defined::user_defined_aggregates::test_setup ... ok +test user_defined::user_defined_aggregates::test_udaf_as_window ... ok +test user_defined::relation_planner::tests::virtual_table_filters_and_aggregation ... ok +test user_defined::user_defined_aggregates::test_udaf_as_window_with_frame ... ok +test user_defined::user_defined_aggregates::test_udaf ... ok +test user_defined::user_defined_aggregates::test_groups_accumulator ... ok +test user_defined::user_defined_aggregates::test_udaf_as_window_with_frame_without_retract_batch ... ok +test user_defined::user_defined_aggregates::test_udaf_returning_struct ... ok +test user_defined::user_defined_aggregates::test_metadata_based_aggregate_as_window ... ok +test user_defined::user_defined_async_scalar_functions::test_async_udf_with_non_modular_batch_size ... ok +test user_defined::user_defined_async_scalar_functions::test_async_udf_metrics ... ok +test user_defined::user_defined_plan::normal_query_with_analyzer ... ok +test user_defined::user_defined_aggregates::test_udaf_shadows_builtin_fn ... ok +test user_defined::user_defined_aggregates::test_udaf_returning_struct_subquery ... ok +test user_defined::user_defined_aggregates::test_user_defined_functions_with_alias ... ok +test user_defined::user_defined_scalar_functions::case_sensitive_identifiers_user_defined_functions ... ok +test user_defined::user_defined_scalar_functions::create_scalar_function_from_sql_statement_postgres_syntax ... ok +test user_defined::user_defined_scalar_functions::create_scalar_function_from_sql_statement_named_arguments ... ok +test user_defined::user_defined_scalar_functions::deregister_udf ... ok +test user_defined::user_defined_plan::topk_query ... ok +test user_defined::user_defined_scalar_functions::scalar_udf_override_built_in_scalar_function ... ok +test user_defined::user_defined_plan::topk_plan ... ok +test user_defined::user_defined_scalar_functions::create_scalar_function_from_sql_statement ... ok +test user_defined::user_defined_scalar_functions::test_config_options_work_for_scalar_func ... ok +test user_defined::user_defined_plan::normal_query ... ok +test user_defined::user_defined_scalar_functions::test_extension_based_udf ... ok +test user_defined::user_defined_scalar_functions::scalar_udf ... ok +test user_defined::user_defined_scalar_functions::scalar_udf_zero_params ... ok +test user_defined::user_defined_scalar_functions::test_metadata_based_udf ... ok +test user_defined::user_defined_scalar_functions::test_extension_metadata_preserve_in_sql_values ... ok +test user_defined::user_defined_scalar_functions::test_metadata_based_udf_with_literal ... ok +test user_defined::user_defined_scalar_functions::csv_query_custom_udf_with_cast ... ok +test user_defined::user_defined_scalar_functions::create_scalar_function_from_sql_statement_default_arguments ... ok +test user_defined::user_defined_plan::topk_invariants_after_invalid_mutation ... ok +test user_defined::user_defined_scalar_functions::test_user_defined_sql_functions ... ok +test user_defined::user_defined_scalar_functions::test_parameterized_scalar_udf ... ok +test user_defined::user_defined_scalar_functions::test_row_mismatch_error_in_scalar_udf ... ok +test user_defined::user_defined_scalar_functions::test_extension_metadata_preserve_in_subquery ... ok +test user_defined::user_defined_plan::topk_invariants ... ok +test user_defined::user_defined_scalar_functions::udaf_as_window_func ... ok +test user_defined::user_defined_window_functions::test_default_expressions ... ok +test user_defined::user_defined_scalar_functions::test_user_defined_functions_cast_to_i64 ... ok +test user_defined::user_defined_table_functions::test_deregister_udtf ... ok +test user_defined::user_defined_window_functions::test_deregister_udwf ... ok +test user_defined::user_defined_scalar_functions::test_user_defined_functions_with_alias ... ok +test user_defined::user_defined_table_functions::test_udtf_type_coercion ... ok +test user_defined::user_defined_scalar_functions::csv_query_avg_sqrt ... ok +test user_defined::user_defined_window_functions::test_metadata_based_window_fn ... ok +test user_defined::user_defined_window_functions::test_setup ... ok +test user_defined::user_defined_window_functions::test_stateful_udwf_bounded_window ... ok +test user_defined::user_defined_window_functions::test_udwf ... ok +test user_defined::user_defined_window_functions::test_stateful_udwf ... ok +test user_defined::user_defined_window_functions::test_udwf_bounded_query_include_rank ... ok +test user_defined::user_defined_scalar_functions::volatile_scalar_udf_with_params ... ok +test user_defined::user_defined_window_functions::test_udwf_bounded_window_returns_null ... ok +test user_defined::user_defined_window_functions::test_udwf_bounded_window ... ok +test user_defined::user_defined_scalar_functions::verify_udf_return_type ... ok +test user_defined::user_defined_window_functions::test_udwf_bounded_window_ignores_frame ... ok +test user_defined::user_defined_window_functions::test_udwf_query_include_rank ... ok +test user_defined::user_defined_window_functions::test_udwf_with_alias ... ok +test user_defined::user_defined_plan::normal_query_without_schemas ... ok +test user_defined::user_defined_table_functions::test_simple_read_csv_udtf ... ok + +test result: ok. 79 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.12s + + Running unittests src/lib.rs (target/debug/deps/datafusion_benchmarks-823daa6f08bd493e) + +running 1 test +test util::options::tests::test_parse_memory_limit_all ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/bin/dfbench.rs (target/debug/deps/dfbench-bf09b4b3bc90f1a2) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/bin/external_aggr.rs (target/debug/deps/external_aggr-cf5625c364395fef) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/bin/imdb.rs (target/debug/deps/imdb-9550b2ee1871df6e) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/bin/mem_profile.rs (target/debug/deps/mem_profile-0e3fe8559b60ce27) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_catalog-5aaa859ed9fdcea8) + +running 8 tests +test listing_schema::tests::dir_table_path_str_does_not_end_with_slash_when_not_is_dir ... ok +test listing_schema::tests::table_path_ends_with_slash_when_is_dir ... ok +test default_table_source::preserves_table_type ... ok +test r#async::tests::test_async_catalog_provider_list_resolve ... ok +test r#async::tests::test_async_catalog_provider_resolve ... ok +test r#async::tests::test_async_schema_provider_resolve ... ok +test information_schema::tests::make_tables_uses_table_type ... ok +test r#async::tests::test_defaults ... ok + +test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/mod.rs (target/debug/deps/datafusion_catalog_listing-d6d492e314729c4e) + +running 12 tests +test table::tests::test_derive_common_ordering_empty_groups ... ok +test table::tests::test_derive_common_ordering_all_none ... ok +test helpers::tests::test_split_files ... ok +test helpers::tests::test_parse_partitions_for_path ... ok +test table::tests::test_derive_common_ordering_mixed_with_none ... ok +test table::tests::test_derive_common_ordering_single_file ... ok +test table::tests::test_derive_common_ordering_no_common_prefix ... ok +test table::tests::test_derive_common_ordering_common_prefix ... ok +test table::tests::test_derive_common_ordering_all_files_same_ordering ... ok +test helpers::tests::test_evaluate_date_partition_prefix ... ok +test helpers::tests::test_evaluate_partition_prefix ... ok +test helpers::tests::test_expr_applicable_for_cols ... ok + +test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_cli-a0908bca27896096) + +running 60 tests +test catalog::tests::test_substitute_tilde ... ok +test catalog::tests::query_s3_location_test ... ok +test exec::tests::copy_to_external_object_store_test ... ok +test command::tests::command_execute_profile_mode ... ok +test catalog::tests::query_invalid_location_test ... ok +test helper::tests::sql_dialect ... ok +test helper::tests::test_split_from_semicolon ... ok +test helper::tests::unescape_readline_input ... ok +test highlighter::tests::highlighter_invalid ... ok +test highlighter::tests::highlighter_valid ... ok +test highlighter::tests::highlighter_valid_with_new_line ... ok +test object_storage::instrumented::tests::instrumented_mode ... ok +test exec::tests::create_external_table_format_option ... ok +test object_storage::instrumented::tests::instrumented_registry ... ok +test exec::tests::create_external_table_local_file ... ok +test object_storage::instrumented::tests::instrumented_store_delete ... ok +test object_storage::instrumented::tests::instrumented_store_copy_if_not_exists ... ok +test object_storage::instrumented::tests::instrumented_store_get ... ok +test object_storage::instrumented::tests::instrumented_store_copy ... ok +test object_storage::instrumented::tests::instrumented_store_head ... ok +test object_storage::instrumented::tests::instrumented_store_list ... ok +test object_storage::instrumented::tests::instrumented_store_list_with_delimiter ... ok +test object_storage::instrumented::tests::instrumented_store_put_opts ... ok +test object_storage::instrumented::tests::request_details ... ok +test object_storage::instrumented::tests::instrumented_store_put_multipart ... ok +test exec::tests::create_object_store_table_gcs ... ok +test object_storage::tests::gcs_object_store_builder ... ok +test object_storage::tests::oss_object_store_builder ... ok +test object_storage::tests::s3_object_store_builder ... ok +test object_storage::tests::s3_object_store_builder_allow_http_error ... ok +test object_storage::tests::s3_object_store_builder_default ... ok +test object_storage::tests::s3_object_store_builder_overrides_region_when_resolve_region_enabled ... ok +test object_storage::tests::s3_object_store_builder_resolves_region_when_none_provided ... ok +test print_format::tests::print_automatic_no_header ... ok +test object_storage::instrumented::tests::request_summary_only_duration ... ok +test object_storage::instrumented::tests::request_summary_neither_duration_or_size ... ok +test object_storage::instrumented::tests::request_summary_only_size ... ok +test print_format::tests::print_csv_no_header ... ok +test print_format::tests::print_automatic_with_header ... ok +test print_format::tests::print_csv_with_header ... ok +test print_format::tests::print_empty ... ok +test object_storage::instrumented::tests::request_summary ... ok +test print_format::tests::print_maxrows_limited_one_batch ... ok +test print_format::tests::print_maxrows_limited_multi_batched ... ok +test print_format::tests::print_json ... ok +test print_format::tests::print_ndjson ... ok +test print_format::tests::print_tsv_no_header ... ok +test print_format::tests::print_tsv_with_header ... ok +test print_format::tests::print_table ... ok +test print_options::tests::write_output ... ok +test print_format::tests::test_print_batches_empty_batch ... ok +test print_format::tests::print_maxrows_unlimited ... ok +test print_format::tests::test_print_batches_empty_batches ... ok +test exec::tests::create_object_store_table_http ... ok +test exec::tests::create_object_store_table_cos ... ok +test catalog::tests::query_http_location_test ... ok +test exec::tests::create_object_store_table_oss ... ok +test exec::tests::copy_to_object_store_table_s3 ... ok +test exec::tests::create_object_store_table_s3 ... ok +test catalog::tests::query_gs_location_test ... ok + +test result: ok. 60 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.65s + + Running unittests src/main.rs (target/debug/deps/datafusion_cli-38908b37022e0098) + +running 7 tests +test tests::memory_pool_size ... ok +test tests::test_parquet_metadata_works_with_strings ... ok +test tests::test_statistics_cache_override ... ok +test tests::test_statistics_cache_default ... ok +test tests::test_list_files_cache ... ok +test tests::test_parquet_metadata_works ... ok +test tests::test_metadata_cache ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s + + Running tests/cli_integration.rs (target/debug/deps/cli_integration-14cf728ce4e53a6e) + +running 22 tests +test test_aws_options ... ok +test test_cli ... ok +test test_aws_region_auto_resolution ... ok +test test_cli_format::case_1 ... ok +test cli_quick_test::case_7_change_format_version ... ok +test cli_quick_test::case_2_exec_backslash ... ok +test cli_quick_test::case_6_can_see_indent_format ... ok +test test_cli_format::case_4 ... ok +test cli_quick_test::case_1_exec_multiple_statements ... ok +test cli_explain_environment_overrides ... ok +test cli_quick_test::case_3_exec_from_files ... ok +test cli_quick_test::case_4_set_batch_size ... ok +test test_object_store_profiling ... ok +test test_s3_url_fallback ... ok +test cli_quick_test::case_5_default_explain_plan ... ok +test test_cli_format::case_2 ... ok +test test_cli_format::case_3 ... ok +test test_cli_format::case_6 ... ok +test test_cli_format::case_5 ... ok +test test_cli_top_memory_consumers::case_1 ... ok +test test_cli_top_memory_consumers::case_2 ... ok +test test_cli_top_memory_consumers::case_3 ... ok + +test result: ok. 22 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.90s + + Running unittests src/lib.rs (target/debug/deps/datafusion_common-be5e38e0c0a2afb2) + +running 376 tests +test config::tests::reset_nested_scalar_reports_helpful_error ... ok +test config::tests::csv_u8_table_options ... ok +test config::tests::alter_test_extension_config ... ok +test config::tests::create_table_config ... ok +test config::tests::iter_test_extension_config ... ok +test config::tests::test_parquet_writer_version_validation ... ok +test config::tests::parquet_encryption_factory_config ... ok +test config::tests::warning_only_not_default ... ok +test config::tests::parquet_table_options ... ok +test config::tests::parquet_table_options_config_metadata_entry ... ok +test dfschema::tests::into ... ok +test config::tests::parquet_table_options_config_entry ... ok +test config::tests::parquet_table_parquet_options_config_entry ... ok +test cse::test::id_array_visitor ... ok +test dfschema::tests::from_qualified_schema ... ok +test dfschema::tests::from_unqualified_schema ... ok +test dfschema::tests::join_unqualified_duplicate ... ok +test dfschema::tests::test_contain_column ... ok +test dfschema::tests::join_qualified_duplicate ... ok +test dfschema::tests::join_mixed_duplicate ... ok +test dfschema::tests::test_datatype_is_logically_equal ... ok +test dfschema::tests::join_mixed ... ok +test dfschema::tests::select_without_valid_fields ... ok +test dfschema::tests::join_qualified ... ok +test dfschema::tests::test_datatype_is_logically_equivalent_to_dictionary ... ok +test dfschema::tests::test_datatype_is_not_semantically_equivalent_to_dictionary ... ok +test dfschema::tests::test_datatype_is_semantically_equal ... ok +test dfschema::tests::test_dfschema_to_schema_conversion ... ok +test dfschema::tests::test_from_field_specific_qualified_schema ... ok +test dfschema::tests::test_from_qualified_fields ... ok +test dfschema::tests::qualifier_in_name ... ok +test dfschema::tests::helpful_error_messages ... ok +test dfschema::tests::quoted_qualifiers_in_name ... ok +test column::tests::test_normalize_with_schemas_and_ambiguity_check ... ok +test display::human_readable::tests::test_human_readable_count ... ok +test display::human_readable::tests::test_human_readable_duration ... ok +test error::test::arrow_error_to_datafusion ... ok +test error::test::datafusion_error_to_arrow ... ok +test error::test::external_error ... ok +test error::test::external_error_no_recursive ... ok +test config::tests::parquet_table_encryption ... ok +test error::test::test_assert_eq_or_internal_err_passes ... ok +test dfschema::tests::from_qualified_schema_into_arrow_schema ... ok +test dfschema::tests::test_print_schema_qualified ... ok +test error::test::test_assert_eq_or_internal_err_fails ... ok +test error::test::test_assert_ne_or_internal_err_fails ... ok +test dfschema::tests::test_print_schema_complex_types ... ok +test dfschema::tests::test_print_schema_edge_case_types ... ok +test dfschema::tests::test_print_schema_complex_type_combinations ... ok +test dfschema::tests::test_print_schema_empty ... ok +test dfschema::tests::test_print_schema_mixed_qualified_unqualified ... ok +test error::test::test_assert_ne_or_internal_err_passes ... ok +test dfschema::tests::test_print_schema_unqualified ... ok +test dfschema::tests::test_print_schema_array_of_map ... ok +test dfschema::tests::test_print_schema_deeply_nested_types ... ok +test error::test::test_assert_or_internal_err_passes ... ok +test error::test::test_assert_or_internal_err_fails_default ... ok +test error::test::test_disabled_backtrace ... ok +test error::test::test_assert_or_internal_err_fails_with_message ... ok +test error::test::test_error_size ... ok +test error::test::test_assert_or_internal_err_with_format_arguments ... ok +test error::test::test_find_root_error ... ok +test error::test::test_iter ... ok +test error::test::test_make_error_parse_input ... ok +test file_options::tests::test_writeroptions_json_from_statement_options ... ok +test file_options::tests::test_writeroptions_csv_from_statement_options ... ok +test functional_dependencies::tests::constraints_iter ... ok +test functional_dependencies::tests::test_get_updated_id_keys ... ok +test functional_dependencies::tests::test_project_constraints ... ok +test file_options::parquet_writer::tests::test_defaults_match ... ok +test file_options::tests::test_writeroptions_parquet_from_statement_options ... ok +test file_options::parquet_writer::tests::table_parquet_opts_to_writer_props ... ok +test file_options::tests::test_writeroptions_parquet_column_specific ... ok +test file_options::parquet_writer::tests::table_parquet_opts_to_writer_props_skip_arrow_metadata ... ok +test file_options::parquet_writer::tests::test_bloom_filter_defaults ... ok +test file_options::parquet_writer::tests::test_bloom_filter_set_ndv_only ... ok +test file_options::parquet_writer::tests::test_bloom_filter_set_fpp_only ... ok +test hash_utils::tests::create_hashes_fixed_size_binary ... ok +test hash_utils::tests::binary_array ... ok +test hash_utils::tests::binary_view_array ... ok +test hash_utils::tests::create_hashes_for_large_list_view_arrays ... ok +test hash_utils::tests::create_hashes_for_empty_fixed_size_lit ... ok +test hash_utils::tests::create_hashes_for_list_view_arrays ... ok +test hash_utils::tests::create_hashes_for_fixed_size_list_arrays ... ok +test hash_utils::tests::create_hashes_for_decimal_array ... ok +test hash_utils::tests::create_hashes_for_float_arrays ... ok +test hash_utils::tests::create_hashes_for_sparse_union_arrays ... ok +test hash_utils::tests::create_hashes_for_sparse_union_arrays_with_nulls ... ok +test hash_utils::tests::create_hashes_for_dense_union_arrays ... ok +test hash_utils::tests::create_hashes_for_sliced_list_arrays ... ok +test hash_utils::tests::create_hashes_for_list_arrays ... ok +test hash_utils::tests::create_hashes_for_struct_arrays ... ok +test hash_utils::tests::create_hashes_for_map_arrays ... ok +test hash_utils::tests::large_binary_array ... ok +test hash_utils::tests::large_string_array ... ok +test hash_utils::tests::create_hashes_for_dict_arrays ... ok +test hash_utils::tests::dict_string_array ... ok +test hash_utils::tests::create_multi_column_hash_for_dict_arrays ... ok +test hash_utils::tests::string_array ... ok +test hash_utils::tests::test_create_hashes_equivalence ... ok +test hash_utils::tests::string_view_array ... ok +test hash_utils::tests::test_create_hashes_from_arrays ... ok +test hash_utils::tests::create_multi_column_hash_with_run_array ... ok +test hash_utils::tests::create_hashes_for_run_array ... ok +test hash_utils::tests::test_create_hashes_from_dyn_arrays ... ok +test hash_utils::tests::create_hashes_for_sliced_run_array ... ok +test hash_utils::tests::test_run_array_with_nulls ... ok +test hash_utils::tests::test_run_array_with_nulls_multicolumn ... ok +test hash_utils::tests::test_with_hashes_empty_arrays ... ok +test nested_struct::tests::test_cast_null_struct_field_to_nested_struct ... ok +test hash_utils::tests::create_hashes_for_struct_arrays_more_column_than_row ... ok +test nested_struct::tests::test_cast_struct_incompatible_child_type ... ok +test nested_struct::tests::test_cast_struct_missing_non_nullable_field_fails ... ok +test hash_utils::tests::test_with_hashes ... ok +test hash_utils::tests::test_with_hashes_multi_column ... ok +test hash_utils::tests::test_with_hashes_reentrancy ... ok +test nested_struct::tests::test_cast_struct_missing_nullable_field_succeeds ... ok +test nested_struct::tests::test_cast_struct_source_not_struct ... ok +test nested_struct::tests::test_validate_struct_compatibility_additional_field_in_source ... ok +test nested_struct::tests::test_cast_struct_with_missing_field ... ok +test nested_struct::tests::test_cast_struct_with_array_and_map_fields ... ok +test nested_struct::tests::test_validate_struct_compatibility_by_name ... ok +test nested_struct::tests::test_validate_struct_compatibility_by_name_missing_required_field ... ok +test nested_struct::tests::test_validate_struct_compatibility_by_name_with_type_mismatch ... ok +test nested_struct::tests::test_validate_struct_compatibility_compatible_types ... ok +test nested_struct::tests::test_validate_struct_compatibility_incompatible_types ... ok +test nested_struct::tests::test_validate_struct_compatibility_missing_field_in_source ... ok +test nested_struct::tests::test_validate_struct_compatibility_mixed_name_overlap ... ok +test nested_struct::tests::test_validate_struct_compatibility_nested_nullable_to_non_nullable ... ok +test nested_struct::tests::test_validate_struct_compatibility_non_nullable_to_nullable ... ok +test nested_struct::tests::test_validate_struct_compatibility_nullable_to_non_nullable ... ok +test nested_struct::tests::test_validate_struct_compatibility_partial_name_overlap_with_count_mismatch ... ok +test nested_struct::tests::test_validate_struct_compatibility_positional_no_overlap_mismatch_len ... ok +test nested_struct::tests::test_validate_struct_compatibility_positional_with_type_mismatch ... ok +test nested_struct::tests::test_cast_simple_column ... ok +test nested_struct::tests::test_cast_struct_positional_when_no_overlap ... ok +test nested_struct::tests::test_cast_struct_field_order_differs ... ok +test nested_struct::tests::test_cast_nested_struct_with_extra_and_missing_fields ... ok +test nested_struct::tests::test_cast_struct_parent_nulls_retained ... ok +test rounding::tests::test_next_down ... ok +test rounding::tests::test_next_down_nan ... ok +test rounding::tests::test_next_down_nan_f32 ... ok +test nested_struct::tests::test_cast_column_with_options ... ok +test rounding::tests::test_next_down_neg_infinity ... ok +test pruning::tests::test_statistics_pruning_statistics_empty ... ok +test rounding::tests::test_next_down_neg_infinity_f32 ... ok +test rounding::tests::test_next_down_small_negative ... ok +test rounding::tests::test_next_down_small_negative_f32 ... ok +test pruning::tests::test_composite_pruning_statistics_priority ... ok +test rounding::tests::test_next_down_small_positive ... ok +test rounding::tests::test_next_down_small_positive_f32 ... ok +test rounding::tests::test_next_down_zero_f32 ... ok +test rounding::tests::test_next_down_zero_f64 ... ok +test rounding::tests::test_next_up_nan ... ok +test rounding::tests::test_next_up_nan_f32 ... ok +test rounding::tests::test_next_up_neg_zero_f32 ... ok +test rounding::tests::test_next_up_neg_zero_f64 ... ok +test rounding::tests::test_next_up_pos_infinity ... ok +test pruning::tests::test_partition_pruning_statistics_empty ... ok +test rounding::tests::test_next_up_pos_infinity_f32 ... ok +test rounding::tests::test_next_up_small_negative ... ok +test rounding::tests::test_next_up_small_negative_f32 ... ok +test rounding::tests::test_next_up_small_positive ... ok +test pruning::tests::test_composite_pruning_statistics_empty_and_mismatched_containers ... ok +test rounding::tests::test_next_up_small_positive_f32 ... ok +test pruning::tests::test_statistics_pruning_statistics ... ok +test scalar::struct_builder::tests::test_empty_struct ... ok +test scalar::tests::cast_date_to_timestamp_overflow_returns_error ... ok +test scalar::tests::f16_test_overflow ... ok +test scalar::tests::dense_scalar_union_is_null ... ok +test pruning::tests::test_partition_pruning_statistics_multiple_negative_values ... ok +test pruning::tests::test_composite_pruning_statistics_partition_and_file ... ok +test pruning::tests::test_partition_pruning_statistics_multiple_positive_values ... ok +test scalar::tests::expect_sub_error ... ok +test scalar::tests::expect_add_error ... ok +test pruning::tests::test_partition_pruning_statistics ... ok +test pruning::tests::test_partition_pruning_statistics_null_in_values ... ok +test scalar::tests::memory_size ... ok +test scalar::tests::null_dictionary_scalar_produces_null_dictionary_array ... ok +test scalar::tests::scalar_decimal_test ... ok +test scalar::tests::scalar_iter_to_array_empty ... ok +test scalar::tests::scalar_add_trait_test ... ok +test scalar::tests::decimal_operations_with_nulls ... ok +test scalar::tests::decimal_operations ... ok +test scalar::tests::scalar_iter_to_array_mismatched_types ... ok +test scalar::tests::scalar_large_list_null_to_array ... ok +test scalar::tests::scalar_add_overflow_test ... ok +test scalar::tests::scalar_list_null_to_array ... ok +test scalar::tests::scalar_large_list_to_array ... ok +test scalar::tests::scalar_list_to_array ... ok +test scalar::tests::scalar_iter_to_dictionary ... ok +test scalar::tests::scalar_sub_trait_int32_overflow_test ... ok +test scalar::tests::iter_to_array_primitive_test ... ok +test scalar::tests::scalar_sub_trait_int64_overflow_test ... ok +test scalar::tests::scalar_sub_trait_int32_test ... ok +test scalar::tests::iter_to_array_string_test ... ok +test scalar::tests::scalar_sub_trait_int64_test ... ok +test scalar::tests::scalar_timestamp_ns_utc_timezone ... ok +test scalar::tests::scalar_sub_trait_test ... ok +test scalar::tests::scalar_eq_array ... ok +test scalar::tests::scalar_iter_to_array_boolean ... ok +test scalar::tests::scalar_try_from_array_list_array_null ... ok +test scalar::tests::scalar_partial_ordering ... ok +test scalar::tests::scalar_try_from_array_null ... ok +test scalar::tests::scalar_try_from_dict_datatype ... ok +test scalar::tests::scalar_try_from_list_datatypes ... ok +test scalar::tests::scalar_try_from_list_of_list ... ok +test scalar::tests::scalar_try_from_not_equal_list_nested_list ... ok +test scalar::tests::round_trip ... ok +test scalar::tests::scalar_value_to_array_u32 ... ok +test scalar::tests::scalar_value_to_array_u64 ... ok +test scalar::tests::cast_round_trip ... ok +test scalar::tests::size_of_scalar ... ok +test scalar::tests::sparse_scalar_union_is_null ... ok +test scalar::tests::test_binary_debug ... ok +test scalar::tests::test_binary_display ... ok +test scalar::tests::test_build_timestamp_millisecond_list ... ok +test scalar::tests::test_display_date64_large_values ... ok +test scalar::tests::test_convert_array_to_scalar_vec ... ok +test scalar::tests::test_distance_none ... ok +test scalar::tests::test_eq_array_err_message ... ok +test scalar::tests::test_format_timestamp_type_for_error_and_bounds ... ok +test scalar::tests::test_iter_to_array_fixed_size_list ... ok +test scalar::tests::test_iter_to_array_struct_with_nulls ... ok +test scalar::tests::test_iter_to_array_struct ... ok +test scalar::tests::test_list_scalar_eq_to_array ... ok +test scalar::tests::test_list_to_array_string ... ok +test scalar::tests::test_min_max_float16 ... ok +test scalar::tests::test_min_max_with_timezone ... ok +test scalar::tests::test_list_partial_cmp ... ok +test scalar::tests::test_lists_in_struct ... ok +test scalar::tests::test_nested_lists ... ok +test scalar::tests::test_new_default_interval ... ok +test scalar::tests::test_new_default ... ok +test scalar::tests::test_interval_add_timestamp ... ok +test scalar::tests::test_new_negative_one_decimal128 ... ok +test scalar::tests::test_new_one_decimal128 ... ok +test scalar::tests::test_new_one_decimal256 ... ok +test scalar::tests::test_new_ten_decimal128 ... ok +test scalar::tests::test_new_ten_decimal256 ... ok +test scalar::tests::test_newlist_timestamp_zone ... ok +test scalar::tests::test_scalar_distance ... ok +test scalar::tests::test_scalar_distance_invalid ... ok +test scalar::tests::test_scalar_interval_negate ... ok +test scalar::tests::test_scalar_interval_add ... ok +test scalar::tests::test_scalar_interval_sub ... ok +test scalar::tests::test_scalar_max ... ok +test scalar::tests::test_scalar_min ... ok +test scalar::tests::test_scalar_negative ... ok +test scalar::tests::test_scalar_negative_overflows ... ok +test scalar::tests::test_scalar_union_dense ... ok +test scalar::tests::test_scalar_union_sparse ... ok +test scalar::tests::test_scalar_value_from_for_map ... ok +test scalar::tests::test_scalar_value_from_for_struct ... ok +test scalar::tests::test_scalar_value_from_string ... ok +test scalar::tests::test_scalar_value_try_new_null ... ok +test scalar::tests::test_to_array_of_size_for_none_fsb ... ok +test scalar::tests::test_to_array_of_size_for_fsl ... ok +test scalar::tests::test_try_cmp ... ok +test scalar::tests::test_to_array_of_size_for_nested ... ok +test scalar::tests::test_views_minimize_memory ... ok +test stats::tests::test_add ... ok +test stats::tests::test_byte_size_to_inexact ... ok +test stats::tests::test_byte_size_try_merge ... ok +test stats::tests::test_add_scalar ... ok +test scalar::tests::test_scalar_struct ... ok +test stats::tests::test_get_value ... ok +test stats::tests::test_is_exact ... ok +test scalar::tests::test_struct_display_null ... ok +test stats::tests::test_map ... ok +test scalar::tests::test_map_display_and_debug ... ok +test scalar::tests::test_null_bug ... ok +test stats::tests::test_max ... ok +test stats::tests::test_multiply ... ok +test stats::tests::test_min ... ok +test scalar::tests::test_struct_display ... ok +test stats::tests::test_precision_cloning ... ok +test stats::tests::test_multiply_scalar ... ok +test stats::tests::test_project_empty ... ok +test stats::tests::test_project_none ... ok +test stats::tests::test_cast_to ... ok +test stats::tests::test_project_repeated ... ok +test stats::tests::test_project_swap ... ok +test stats::tests::test_sub ... ok +test stats::tests::test_sub_scalar ... ok +test stats::tests::test_to_inexact ... ok +test stats::tests::test_try_merge_basic ... ok +test stats::tests::test_try_merge_distinct_count_absent ... ok +test stats::tests::test_try_merge_mismatched_size ... ok +test stats::tests::test_with_byte_size_builder ... ok +test stats::tests::test_with_fetch_absent_stats ... ok +test stats::tests::test_try_merge_mixed_precision ... ok +test stats::tests::test_with_fetch_basic_preservation ... ok +test stats::tests::test_try_merge_empty ... ok +test scalar::tests::test_struct_nulls ... ok +test stats::tests::test_with_fetch_fetch_exceeds_rows ... ok +test stats::tests::test_with_fetch_inexact_input ... ok +test stats::tests::test_with_fetch_multi_partition ... ok +test stats::tests::test_with_fetch_no_limit ... ok +test stats::tests::test_with_fetch_preserves_all_column_stats ... ok +test stats::tests::test_with_fetch_scales_byte_size ... ok +test stats::tests::test_with_fetch_skip_all_rows ... ok +test stats::tests::test_with_fetch_total_byte_size_fallback ... ok +test stats::tests::test_with_fetch_with_skip ... ok +test table_reference::tests::test_table_reference_from_str_normalizes ... ok +test table_reference::tests::test_table_reference_to_vector ... ok +test test_util::tests::test_create_record_batch ... ok +test tests::test_downcast_value ... ok +test test_util::tests::test_data_dir ... ok +test test_util::tests::test_happy ... ok +test tests::test_downcast_value_err_message ... ok +test tree_node::tests::test_apply ... ok +test tree_node::tests::test_apply_and_visit_references ... ok +test tree_node::tests::test_apply_f_down_jump_on_a ... ok +test tree_node::tests::test_apply_f_down_jump_on_e ... ok +test tree_node::tests::test_apply_f_down_stop_on_a ... ok +test tree_node::tests::test_apply_f_down_stop_on_e ... ok +test tree_node::tests::test_rewrite ... ok +test tree_node::tests::test_rewrite_f_down_jump_on_e ... ok +test tree_node::tests::test_rewrite_f_down_stop_on_a ... ok +test tree_node::tests::test_rewrite_f_down_jump_on_a ... ok +test tree_node::tests::test_rewrite_f_down_stop_on_e ... ok +test tree_node::tests::test_rewrite_f_up_jump_on_a ... ok +test tree_node::tests::test_rewrite_f_up_jump_on_e ... ok +test tree_node::tests::test_rewrite_f_up_stop_on_a ... ok +test tree_node::tests::test_rewrite_f_up_stop_on_e ... ok +test tree_node::tests::test_transform ... ok +test tree_node::tests::test_transform_down ... ok +test tree_node::tests::test_transform_down_f_down_jump_on_a ... ok +test tree_node::tests::test_transform_down_f_down_jump_on_e ... ok +test scalar::tests::test_scalar_value_from_for_struct_should_panic - should panic ... ok +test tree_node::tests::test_transform_down_f_down_stop_on_a ... ok +test tree_node::tests::test_transform_down_f_down_stop_on_e ... ok +test tree_node::tests::test_transform_f_down_jump_on_a ... ok +test tree_node::tests::test_transform_f_down_jump_on_e ... ok +test tree_node::tests::test_transform_f_down_stop_on_a ... ok +test tree_node::tests::test_transform_f_down_stop_on_e ... ok +test tree_node::tests::test_transform_f_up_jump_on_a ... ok +test tree_node::tests::test_transform_f_up_jump_on_e ... ok +test tree_node::tests::test_transform_f_up_stop_on_a ... ok +test tree_node::tests::test_transform_up ... ok +test tree_node::tests::test_transform_f_up_stop_on_e ... ok +test tree_node::tests::test_transform_up_f_up_jump_on_e ... ok +test tree_node::tests::test_transform_up_f_up_stop_on_a ... ok +test tree_node::tests::test_transform_up_f_up_jump_on_a ... ok +test tree_node::tests::test_visit ... ok +test tree_node::tests::test_transform_up_f_up_stop_on_e ... ok +test tree_node::tests::test_visit_f_down_jump_on_a ... ok +test tree_node::tests::test_visit_f_down_jump_on_e ... ok +test tree_node::tests::test_visit_f_down_stop_on_a ... ok +test tree_node::tests::test_visit_f_down_stop_on_e ... ok +test tree_node::tests::test_visit_f_up_jump_on_a ... ok +test tree_node::tests::test_visit_f_up_jump_on_e ... ok +test tree_node::tests::test_visit_f_up_stop_on_a ... ok +test tree_node::tests::test_visit_f_up_stop_on_e ... ok +test utils::memory::record_batch_tests::test_get_record_batch_memory_size ... ok +test utils::memory::record_batch_tests::test_get_record_batch_memory_size_empty ... ok +test utils::memory::record_batch_tests::test_get_record_batch_memory_size_shared_buffer ... ok +test utils::memory::record_batch_tests::test_get_record_batch_memory_size_nested_array ... ok +test utils::memory::record_batch_tests::test_get_record_batch_memory_size_with_null ... ok +test utils::memory::tests::test_estimate_memory ... ok +test utils::memory::tests::test_estimate_memory_overflow ... ok +test utils::tests::ord_same_type ... ok +test utils::tests::test_bisect_linear_left_and_right ... ok +test utils::tests::test_bisect_linear_left_and_right_diff_sort ... ok +test utils::tests::test_find_indices ... ok +test utils::tests::test_evaluate_partition_ranges ... ok +test utils::tests::test_get_at_indices ... ok +test utils::tests::test_longest_consecutive_prefix ... ok +test utils::tests::test_quote_identifier ... ok +test utils::tests::test_merge_and_order_indices ... ok +test utils::tests::test_transpose ... ok +test utils::tests::test_set_difference ... ok +test utils::tests::vector_ord ... ok +test tree_node::tests::test_large_tree ... ok +test scalar::tests::timestamp_op_random_tests ... ok + +test result: ok. 376 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s + + Running unittests src/lib.rs (target/debug/deps/datafusion_common_runtime-0f0e6e56701b5cdc) + +running 4 tests +test common::tests::cancel_ongoing_task ... ok +test common::tests::cancel_not_started_task ... ok +test common::tests::runtime_shutdown ... ok +test common::tests::panic_resume - should panic ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/mod.rs (target/debug/deps/datafusion_datasource-9673ad2ac7cfa369) + +running 96 tests +test display::tests::file_groups_display_empty ... ok +test display::tests::file_group_display_too_many_default ... ok +test display::tests::file_groups_display_one ... ok +test display::tests::file_group_display_too_many_verbose ... ok +test display::tests::file_groups_display_many_verbose ... ok +test display::tests::file_groups_display_many_default ... ok +test display::tests::file_group_display_many_default ... ok +test display::tests::file_groups_display_too_many_verbose ... ok +test display::tests::file_groups_display_too_many_default ... ok +test file_compression_type::tests::from_str ... ok +test file_groups::test::repartition_empty_file_only ... ok +test file_groups::test::repartition_no_action_min_size ... ok +test file_groups::test::repartition_no_action_zero_files ... ok +test file_groups::test::repartition_ordered_no_action_file_too_small ... ok +test file_groups::test::repartition_ordered_no_action_too_few_partitions ... ok +test file_groups::test::repartition_ordered_one_large_file_with_range ... ok +test file_groups::test::repartition_ordered_one_large_file ... ok +test file_groups::test::repartition_multiple_partitions ... ok +test file_groups::test::repartition_ordered_existing_group_multiple_files ... ok +test file_groups::test::repartition_ordered_one_large_one_small_existing_empty ... ok +test file_groups::test::repartition_ordered_one_large_one_small_file ... ok +test file_groups::test::repartition_empty_files ... ok +test file_groups::test::repartition_ordered_one_large_one_small_file_with_non_full_range ... ok +test file_groups::test::repartition_ordered_one_large_one_small_file_with_full_range ... ok +test file_groups::test::repartition_ordered_one_large_one_small_file_with_split_range ... ok +test file_groups::test::repartition_same_num_partitions ... ok +test file_groups::test::repartition_ordered_two_large_one_small_files ... ok +test file_groups::test::repartition_ordered_two_large_files ... ok +test file_groups::test::repartition_single_file ... ok +test file_groups::test::repartition_single_file_duplicated_with_range ... ok +test file_groups::test::repartition_single_file_with_incomplete_range ... ok +test file_compression_type::tests::test_bgzip_stream_decoding ... ok +test file_groups::test::repartition_single_file_with_range ... ok +test file_groups::test::test_group_by_partition_values_edge_cases ... ok +test file_groups::test::repartition_too_much_partitions ... ok +test file_groups::test::test_group_by_partition_values_more_groups_than_target ... ok +test file_groups::test::test_group_by_partition_values_less_groups_than_target ... ok +test file_scan_config::tests::test_output_partitioning_not_partitioned_by_file_group ... ok +test file_scan_config::tests::test_output_partitioning_no_partition_columns ... ok +test file_scan_config::tests::physical_plan_config_no_projection_tab_cols_as_field ... ok +test file_scan_config::tests::test_output_partitioning_with_partition_columns ... ok +test file_scan_config::tests::test_file_scan_config_builder_defaults ... ok +test file_scan_config::tests::test_file_scan_config_builder ... ok +test file_scan_config::tests::test_file_scan_config_builder_new_from ... ok +test file_stream::tests::on_error_opening_fail ... ok +test file_stream::tests::on_error_scanning_fail ... ok +test file_scan_config::tests::equivalence_properties_after_schema_change ... ok +test file_scan_config::tests::test_partition_statistics_projection ... ok +test memory::tests::new_exec_with_batches ... ok +test memory::tests::new_exec_with_batches_empty ... ok +test memory::memory_source_tests::test_memory_order_eq ... ok +test memory::tests::new_exec_with_batches_invalid_schema ... ok +test memory::tests::new_exec_with_non_nullable_schema ... ok +test file_scan_config::tests::test_split_groups_by_statistics_with_target_partitions ... ok +test file_stream::tests::with_limit_at_middle_of_batch ... ok +test file_stream::tests::without_limit ... ok +test memory::tests::exec_with_limit ... ok +test file_stream::tests::with_limit_between_files ... ok +test file_scan_config::tests::test_split_groups_by_statistics ... ok +test file_stream::tests::on_error_opening ... ok +test memory::tests::values_empty_case ... ok +test file_stream::tests::on_error_scanning ... ok +test file_stream::tests::on_error_mixed ... ok +test projection::test::test_split_projection_boundary_last_file_column ... ok +test projection::test::test_split_projection_expression_with_file_and_partition_columns ... ok +test memory::tests::values_stats_with_nulls_only ... ok +test projection::test::test_split_projection_boundary_first_partition_column ... ok +test projection::test::test_split_projection_interleaved_file_and_partition ... ok +test projection::test::test_split_projection_multiple_partition_columns ... ok +test projection::test::test_split_projection_only_file_columns ... ok +test projection::test::test_split_projection_only_partition_columns ... ok +test projection::test::test_inject_partition_columns_multiple_partitions ... ok +test projection::test::test_split_projection_partition_columns_reverse_order ... ok +test projection::test::test_split_projection_with_partition_columns ... ok +test table_schema::tests::test_add_multiple_partition_columns ... ok +test tests::test_get_store_hdfs ... ok +test tests::test_get_store_file ... ok +test tests::test_object_store_listing_url ... ok +test tests::test_get_store_s3 ... ok +test tests::test_get_store_local ... ok +test table_schema::tests::test_table_schema_creation ... ok +test tests::test_url_contains ... ok +test tests::test_with_statistics_appends_partition_column_stats ... ok +test tests::test_calculate_range_single_line_file ... ok +test url::tests::test_is_collection ... ok +test url::tests::test_cache_serves_partition_from_full_listing ... ok +test url::tests::test_file_extension ... ok +test url::tests::test_prefix_s3 ... ok +test url::tests::test_cache_path_equivalence ... ok +test url::tests::test_split_glob ... ok +test url::tests::test_list_files ... ok +test url::tests::test_prefix_path ... ok +test memory::tests::test_repartition_no_sort_information_no_output_ordering_lopsized_batches ... ok +test memory::tests::test_repartition_with_batch_ordering_not_matching_sizing ... ok +test memory::tests::test_repartition_no_sort_information_no_output_ordering ... ok +test memory::tests::test_repartition_with_sort_information ... ok + +test result: ok. 96 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running unittests src/mod.rs (target/debug/deps/datafusion_datasource_arrow-50e507320c9ff809) + +running 11 tests +test file_format::tests::test_format_detection_corrupted_file ... ok +test file_format::tests::test_format_detection_stream_format ... ok +test file_format::tests::test_format_detection_file_format ... ok +test file_format::tests::test_format_detection_empty_file ... ok +test source::tests::test_arrow_stream_repartitioning_not_supported ... ok +test source::tests::test_stream_opener_errors_with_ranges ... ok +test file_format::tests::test_infer_schema_short_stream ... ok +test file_format::tests::test_infer_schema_stream ... ok +test source::tests::test_stream_opener_with_projection ... ok +test source::tests::test_file_opener_with_ranges ... ok +test source::tests::test_file_opener_without_ranges ... ok + +test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/mod.rs (target/debug/deps/datafusion_datasource_avro-b2824286954bb06c) + +running 18 tests +test avro_to_arrow::arrow_array_reader::test::test_avro_read_nested_list ... ok +test avro_to_arrow::reader::tests::test_avro_basic ... ok +test avro_to_arrow::reader::tests::test_avro_with_projection ... ok +test avro_to_arrow::arrow_array_reader::test::test_avro_read_list ... ok +test avro_to_arrow::arrow_array_reader::test::test_time_avro_milliseconds ... ok +test avro_to_arrow::arrow_array_reader::test::test_avro_iterator ... ok +test avro_to_arrow::arrow_array_reader::test::test_avro_nullable_struct ... ok +test avro_to_arrow::arrow_array_reader::test::test_complex_list ... ok +test avro_to_arrow::arrow_array_reader::test::test_deep_nullable_struct ... ok +test avro_to_arrow::arrow_array_reader::test::test_list_of_structs_with_custom_field_name ... ok +test avro_to_arrow::schema::test::test_alias ... ok +test avro_to_arrow::schema::test::test_invalid_avro_schema ... ok +test avro_to_arrow::arrow_array_reader::test::test_avro_nullable_struct_array ... ok +test avro_to_arrow::schema::test::test_external_props ... ok +test avro_to_arrow::schema::test::test_non_record_schema ... ok +test avro_to_arrow::schema::test::test_nested_schema ... ok +test avro_to_arrow::schema::test::test_plain_types_schema ... ok +test avro_to_arrow::arrow_array_reader::test::test_complex_struct ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/mod.rs (target/debug/deps/datafusion_datasource_csv-1496c1aaba689708) + +running 3 tests +test file_format::tests::test_build_schema_helper_conflicting_types ... ok +test file_format::tests::test_build_schema_helper_type_merging ... ok +test file_format::tests::test_build_schema_helper_different_column_counts ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/mod.rs (target/debug/deps/datafusion_datasource_json-9d858a6fe1c1a70c) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/mod.rs (target/debug/deps/datafusion_datasource_parquet-ce2c14088d40a308) + +running 80 tests +test opener::test::extract_constant_columns_all_null ... ok +test opener::test::extract_constant_columns_non_null ... ok +test opener::test::rewrite_physical_expr_literal ... ok +test access_plan::test::test_only_skips ... ok +test access_plan::test::test_only_scans ... ok +test access_plan::test::test_invalid_too_few ... ok +test access_plan::test::test_invalid_too_many ... ok +test access_plan::test::test_mixed_2 ... ok +test access_plan::test::test_mixed_1 ... ok +test file_format::tests::coerce_int96_to_resolution_with_mixed_timestamps ... ok +test file_format::tests::coerce_int96_to_resolution_with_nested_types ... ok +test metadata::tests::test_has_any_exact_match ... ok +test opener::test::rewrite_projection_to_literals ... ok +test opener::test::test_reverse_scan_single_row_group ... ok +test opener::test::test_reverse_scan_row_groups ... ok +test opener::test::test_reverse_scan_with_non_contiguous_row_groups ... ok +test opener::test::test_prune_on_partition_statistics_with_dynamic_expression ... ok +test opener::test::test_reverse_scan_with_row_selection ... ok +test row_filter::test::complex_expr_doesnt_prevent_pushdown ... ok +test row_filter::test::array_has_any_pushdown_filters_rows ... ok +test row_filter::test::array_has_all_pushdown_filters_rows ... ok +test row_filter::test::mixed_primitive_and_struct_prevents_pushdown ... ok +test row_filter::test::array_has_all_udf_pushdown_filters_rows ... ok +test row_filter::test::array_has_pushdown_filters_rows ... ok +test opener::test::test_opener_pruning_skipped_on_static_filters ... ok +test row_filter::test::basic_expr_doesnt_prevent_pushdown ... ok +test row_filter::test::nested_lists_allow_pushdown_checks ... ok +test row_filter::test::struct_data_structures_prevent_pushdown ... ok +test row_filter::test::array_has_any_udf_pushdown_filters_rows ... ok +test row_filter::test::projected_columns_prevent_pushdown ... ok +test row_filter::test::test_filter_candidate_builder_supports_list_types ... ok +test row_group_filter::tests::remaining_row_group_count_reports_non_skipped_groups ... ok +test opener::test::test_prune_on_partition_value_and_data_value ... ok +test row_filter::test::array_has_udf_pushdown_filters_rows ... ok +test row_group_filter::tests::row_group_pruning_predicate_decimal_type3 ... ok +test row_filter::test::test_filter_type_coercion ... ok +test row_group_filter::tests::row_group_pruning_predicate_decimal_type ... ok +test row_group_filter::tests::row_group_pruning_predicate_decimal_type2 ... ok +test opener::test::test_prune_on_statistics ... ok +test row_group_filter::tests::row_group_pruning_predicate_file_schema ... ok +test row_group_filter::tests::row_group_pruning_predicate_simple_expr ... ok +test row_group_filter::tests::row_group_pruning_predicate_null_expr ... ok +test row_group_filter::tests::row_group_pruning_predicate_missing_stats ... ok +test row_group_filter::tests::row_group_pruning_predicate_decimal_type5 ... ok +test row_group_filter::tests::row_group_pruning_predicate_decimal_type4 ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_simple_expr ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_sql_in ... ok +test row_group_filter::tests::row_group_pruning_predicate_partial_expr ... ok +test row_group_filter::tests::row_group_pruning_predicate_eq_null_expr ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_multiple_expr ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_with_exists_value ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_multiple_expr_view ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_with_exists_2_values ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_with_or_not_eq ... ok +test opener::test::test_prune_on_partition_values_and_file_statistics ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_with_exists_3_values ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_with_exists_3_values_view ... ok +test sort::tests::test_prepared_access_plan_reverse_complex_pattern ... ok +test sort::tests::test_prepared_access_plan_reverse_complex_pattern_detailed ... ok +test sort::tests::test_prepared_access_plan_reverse_alternating_detailed ... ok +test sort::tests::test_prepared_access_plan_reverse_empty_selection ... ok +test sort::tests::test_prepared_access_plan_reverse_alternating_row_groups ... ok +test source::tests::test_parquet_source_predicate_same_as_filter ... ok +test sort::tests::test_prepared_access_plan_reverse_different_row_group_sizes ... ok +test source::tests::test_reverse_scan_builder_pattern ... ok +test source::tests::test_reverse_scan_clone_preserves_value ... ok +test sort::tests::test_prepared_access_plan_reverse_single_row_group ... ok +test source::tests::test_reverse_scan_default_value ... ok +test sort::tests::test_prepared_access_plan_reverse_middle_row_group_only ... ok +test supported_predicates::tests::test_null_check_detection ... ok +test sort::tests::test_prepared_access_plan_reverse_multi_row_group_selection ... ok +test source::tests::test_reverse_scan_independent_of_predicate ... ok +test row_group_filter::tests::test_row_group_bloom_filter_pruning_predicate_without_bloom_filter ... ok +test sort::tests::test_prepared_access_plan_reverse_simple ... ok +test source::tests::test_reverse_scan_with_other_options ... ok +test source::tests::test_reverse_scan_with_setter ... ok +test supported_predicates::tests::test_supported_scalar_functions ... ok +test sort::tests::test_prepared_access_plan_reverse_with_skipped_row_groups ... ok +test sort::tests::test_prepared_access_plan_reverse_with_skipped_row_groups_detailed ... ok +test sort::tests::test_prepared_access_plan_reverse_with_selection ... ok + +test result: ok. 80 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running unittests src/lib.rs (target/debug/deps/datafusion_doc-e3a09afb5087be56) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_examples-7cab19b876545548) + +running 8 tests +test utils::datasets::tests::example_dataset_file_stem ... ok +test utils::datasets::tests::example_dataset_path_points_to_csv ... ok +test utils::datasets::tests::example_dataset_path_str_is_valid_utf8 ... ok +test utils::datasets::tests::regex_schema_is_stable ... ok +test utils::datasets::tests::cars_schema_is_stable ... ok +test utils::csv_to_parquet::tests::test_write_csv_to_parquet_error ... ok +test utils::csv_to_parquet::tests::test_write_csv_to_parquet_with_regex_data ... ok +test utils::csv_to_parquet::tests::test_write_csv_to_parquet_with_cars_data ... ok + +test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running unittests src/lib.rs (target/debug/deps/datafusion_execution-e0b72548ecfca79c) + +running 60 tests +test cache::cache_manager::tests::test_ttl_overridden_when_set_in_config ... ok +test cache::cache_manager::tests::test_ttl_preserved_when_not_set_in_config ... ok +test cache::file_metadata_cache::tests::test_default_file_metadata_cache ... ok +test cache::file_metadata_cache::tests::test_default_file_metadata_cache_with_limit ... ok +test cache::cache_unit::tests::test_cache_invalidation_on_file_modification ... ok +test cache::cache_unit::tests::test_statistics_cache ... ok +test cache::list_files_cache::tests::test_cache_limit_resize ... ok +test cache::list_files_cache::tests::test_drop_table_entries ... ok +test cache::list_files_cache::tests::test_cache_with_ttl ... ok +test cache::list_files_cache::tests::test_cache_with_ttl_and_lru ... ok +test cache::file_metadata_cache::tests::test_default_file_metadata_cache_entries_info ... ok +test cache::list_files_cache::tests::test_basic_operations ... ok +test cache::list_files_cache::tests::test_entry_creation ... ok +test cache::cache_unit::tests::test_list_entries ... ok +test cache::cache_unit::tests::test_ordering_cache ... ok +test cache::cache_unit::tests::test_ordering_cache_invalidation_on_file_modification ... ok +test cache::list_files_cache::tests::test_entry_update_with_size_change ... ok +test cache::list_files_cache::tests::test_lru_eviction_basic ... ok +test cache::list_files_cache::tests::test_lru_ordering_after_access ... ok +test cache::list_files_cache::tests::test_meta_heap_bytes_calculation ... ok +test cache::list_files_cache::tests::test_memory_tracking ... ok +test cache::list_files_cache::tests::test_multiple_evictions ... ok +test cache::list_files_cache::tests::test_nested_partitions ... ok +test cache::list_files_cache::tests::test_prefix_filtering ... ok +test cache::list_files_cache::tests::test_prefix_no_matching_files ... ok +test cache::list_files_cache::tests::test_reject_too_large ... ok +test cache::lru_queue::tests::test_contains_key ... ok +test cache::lru_queue::tests::test_clear ... ok +test cache::lru_queue::tests::test_get ... ok +test cache::lru_queue::tests::test_is_empty ... ok +test cache::lru_queue::tests::test_len ... ok +test cache::lru_queue::tests::test_peek ... ok +test cache::lru_queue::tests::test_put ... ok +test cache::lru_queue::tests::test_remove ... ok +test cache::lru_queue::tests::test_pop ... ok +test disk_manager::tests::test_disabled_disk_manager ... ok +test disk_manager::tests::test_disk_manager_create_spill_folder ... ok +test disk_manager::tests::lazy_temp_dir_creation ... ok +test disk_manager::tests::test_disk_usage_with_clones ... ok +test disk_manager::tests::test_disk_usage_basic ... ok +test disk_manager::tests::test_disk_usage_multiple_files ... ok +test disk_manager::tests::test_disk_usage_clones_dropped_out_of_order ... ok +test memory_pool::tests::test_memory_pool_underflow ... ok +test memory_pool::tests::test_split ... ok +test disk_manager::tests::file_in_right_dir ... ok +test memory_pool::tests::test_id_uniqueness ... ok +test disk_manager::tests::test_temp_file_still_alive_after_disk_manager_dropped ... ok +test memory_pool::tests::test_new_empty ... ok +test memory_pool::tests::test_take ... ok +test object_store::tests::test_get_url_key ... ok +test object_store::tests::test_object_store_url ... ok +test task::tests::task_context_extensions_default ... ok +test task::tests::task_context_extensions ... ok +test memory_pool::pool::tests::test_fair ... ok +test memory_pool::pool::tests::test_tracked_consumers_pool_use_beyond_errors ... ok +test memory_pool::pool::tests::test_tracked_consumers_pool ... ok +test memory_pool::pool::tests::test_tracked_consumers_pool_register ... ok +test memory_pool::pool::tests::test_tracked_consumers_pool_deregister ... ok +test cache::list_files_cache::tests::test_ttl_expiration_in_get ... ok +test cache::lru_queue::tests::test_fuzzy ... ok + +test result: ok. 60 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.73s + + Running unittests src/lib.rs (target/debug/deps/datafusion_expr-83f429cdc8adeb5e) + +running 175 tests +test arguments::tests::test_all_positional ... ok +test arguments::tests::test_all_named ... ok +test arguments::tests::test_unknown_parameter_name ... ok +test arguments::tests::test_missing_required_parameter ... ok +test arguments::tests::test_positional_after_named_error ... ok +test arguments::tests::test_duplicate_parameter_name ... ok +test arguments::tests::test_quoted_parameter_case_sensitive ... ok +test arguments::tests::test_case_insensitive_parameter_matching ... ok +test arguments::tests::test_mixed_case_signature_quoted_matching ... ok +test arguments::tests::test_named_reordering ... ok +test arguments::tests::test_mixed_positional_and_named ... ok +test arguments::tests::test_mixed_case_signature_unquoted_matching ... ok +test execution_props::test::debug ... ok +test async_udf::tests::test_async_udf_partial_eq_and_hash ... ok +test expr::test::format_cast ... ok +test expr::test::test_accept_exprs ... ok +test expr::test::test_is_volatile_scalar_func ... ok +test expr::test::test_logical_ops ... ok +test expr::test::test_display_set_comparison ... ok +test expr::test::test_partial_ord ... ok +test expr::test::test_schema_display_alias_with_relation ... ok +test expr::test::test_schema_display_alias_without_relation ... ok +test expr::test::test_size_of_expr ... ok +test expr_fn::test::filter_is_null_and_is_not_null ... ok +test expr::test::test_display_wildcard ... ok +test expr::test::test_collect_expr ... ok +test expr::test::format_case_when ... ok +test expr::test::infer_placeholder_like_and_similar_to ... ok +test expr::test::infer_placeholder_with_metadata ... ok +test expr::test::infer_placeholder_in_clause ... ok +test conditional_expressions::tests::case_when_same_literal_then_types ... ok +test conditional_expressions::tests::case_when_different_literal_then_types ... ok +test expr_rewriter::guarantees::tests::test_column_single_value ... ok +test expr_rewriter::guarantees::tests::test_not_null_guarantee ... ok +test expr_rewriter::test::rewriter_rewrite ... ok +test expr_rewriter::guarantees::tests::test_inequalities_non_null_unbounded ... ok +test expr_rewriter::guarantees::tests::test_inequalities_maybe_null ... ok +test expr_rewriter::test::rewriter_visit ... ok +test expr_rewriter::test::normalize_cols ... ok +test expr_rewriter::test::unnormalize_cols ... ok +test expr_rewriter::guarantees::tests::test_in_list ... ok +test expr_schema::tests::expr_schema_data_type ... ok +test expr_rewriter::test::test_rewrite_preserving_name ... ok +test expr_rewriter::test::normalize_cols_non_exist ... ok +test expr_schema::tests::expr_schema_nullability ... ok +test expr_schema::tests::test_between_nullability ... ok +test expr_rewriter::order_by::test::preserve_cast ... ok +test expr_schema::tests::test_expr_metadata ... ok +test expr_rewriter::order_by::test::rewrite_sort_cols_by_agg ... ok +test expr_schema::tests::test_expr_placeholder ... ok +test expr_schema::tests::test_inlist_nullability ... ok +test expr_schema::tests::test_like_nullability ... ok +test literal::test::test_lit_nonzero ... ok +test expr_schema::tests::test_scalar_variable ... ok +test literal::test::test_lit_timestamp_nano ... ok +test logical_plan::builder::tests::plan_builder_from_logical_plan ... ok +test expr_rewriter::order_by::test::rewrite_sort_cols_by_agg_alias ... ok +test expr_schema::tests::test_case_expression_nullability ... ok +test logical_plan::builder::tests::plan_builder_intersect_different_num_columns_error ... ok +test logical_plan::builder::tests::plan_builder_empty_name ... ok +test logical_plan::builder::tests::plan_builder_aggregate_without_implicit_group_by_exprs ... ok +test logical_plan::builder::tests::exists_subquery ... ok +test logical_plan::builder::tests::filter_in_subquery ... ok +test logical_plan::builder::tests::plan_builder_sort ... ok +test logical_plan::builder::tests::plan_builder_union ... ok +test logical_plan::builder::tests::plan_builder_schema ... ok +test logical_plan::builder::tests::plan_builder_simple_distinct ... ok +test logical_plan::builder::tests::plan_builder_aggregate_with_implicit_group_by_exprs ... ok +test logical_plan::builder::tests::plan_builder_simple ... ok +test logical_plan::builder::tests::plan_builder_union_distinct ... ok +test logical_plan::builder::tests::stringified_plan ... ok +test logical_plan::builder::tests::projection_non_unique_names ... ok +test logical_plan::builder::tests::test_unique_field_aliases ... ok +test logical_plan::ddl::test::test_partial_ord ... ok +test logical_plan::builder::tests::test_join_metadata ... ok +test logical_plan::invariants::test::wont_fail_extension_plan ... ok +test logical_plan::builder::tests::test_values_metadata ... ok +test logical_plan::display::tests::test_display_empty_schema ... ok +test logical_plan::display::tests::test_display_schema ... ok +test logical_plan::plan::tests::early_stopping_pre_visit ... ok +test logical_plan::builder::tests::select_scalar_subquery ... ok +test logical_plan::builder::tests::test_union_after_join ... ok +test logical_plan::plan::tests::projection_expr_schema_mismatch ... ok +test logical_plan::plan::tests::error_post_visit ... ok +test logical_plan::plan::tests::early_stopping_post_visit ... ok +Snapshot test passes but the existing value is in a legacy format. Please run `cargo insta test --force-update-snapshots` to update to a newer format. Snapshot contents: +// Begin DataFusion GraphViz Plan, +// display it online here: https://dreampuf.github.io/GraphvizOnline + +digraph { + subgraph cluster_1 + { + graph[label="LogicalPlan"] + 2[shape=box label="Projection: employee_csv.id"] + 3[shape=box label="Filter: employee_csv.state IN ()"] + 2 -> 3 [arrowhead=none, arrowtail=normal, dir=back] + 4[shape=box label="Subquery:"] + 3 -> 4 [arrowhead=none, arrowtail=normal, dir=back] + 5[shape=box label="TableScan: employee_csv projection=[state]"] + 4 -> 5 [arrowhead=none, arrowtail=normal, dir=back] + 6[shape=box label="TableScan: employee_csv projection=[id, state]"] + 3 -> 6 [arrowhead=none, arrowtail=normal, dir=back] + } + subgraph cluster_7 + { + graph[label="Detailed LogicalPlan"] + 8[shape=box label="Projection: employee_csv.id\nSchema: [id:Int32]"] + 9[shape=box label="Filter: employee_csv.state IN ()\nSchema: [id:Int32, state:Utf8]"] + 8 -> 9 [arrowhead=none, arrowtail=normal, dir=back] + 10[shape=box label="Subquery:\nSchema: [state:Utf8]"] + 9 -> 10 [arrowhead=none, arrowtail=normal, dir=back] + 11[shape=box label="TableScan: employee_csv projection=[state]\nSchema: [state:Utf8]"] + 10 -> 11 [arrowhead=none, arrowtail=normal, dir=back] + 12[shape=box label="TableScan: employee_csv projection=[id, state]\nSchema: [id:Int32, state:Utf8]"] + 9 -> 12 [arrowhead=none, arrowtail=normal, dir=back] + } +} +// End DataFusion GraphViz Plan +test logical_plan::plan::tests::test_display_indent ... ok +test logical_plan::plan::tests::test_filter_is_scalar ... ok +test logical_plan::plan::tests::error_pre_visit ... ok +test logical_plan::plan::tests::test_display_subquery_alias ... ok +test logical_plan::plan::tests::test_display_pg_json ... ok +test logical_plan::plan::tests::test_display_indent_schema ... ok +test logical_plan::plan::tests::test_join_try_new_schema_validation ... ok +test logical_plan::plan::tests::test_display_graphviz ... ok +test logical_plan::plan::tests::test_join_try_new_with_using_constraint_and_overlapping_columns ... ok +test logical_plan::plan::tests::test_limit_with_new_children ... ok +test logical_plan::plan::tests::test_nullable_schema_after_grouping_set ... ok +test logical_plan::plan::tests::test_join_try_new ... ok +test logical_plan::plan::tests::test_plan_partial_ord ... ok +test logical_plan::plan::tests::test_join_with_new_exprs ... ok +test logical_plan::builder::tests::plan_builder_unnest ... ok +test logical_plan::plan::tests::test_partial_eq_hash_and_partial_ord ... ok +test logical_plan::plan::tests::test_replace_invalid_placeholder ... ok +test logical_plan::plan::tests::test_with_unresolved_placeholders ... ok +test logical_plan::plan::tests::test_replace_placeholder_mismatched_metadata ... ok +test logical_plan::plan::tests::test_transform_explain ... ok +test logical_plan::plan::tests::test_replace_placeholder_empty_relation_valid_schema ... ok +test operation::tests::test_operators ... ok +test logical_plan::plan::tests::test_with_subqueries_jump ... ok +test logical_plan::plan::tests::visit_order ... ok +test predicate_bounds::tests::evaluate_bounds_binary_op ... ok +test predicate_bounds::tests::evaluate_bounds_between ... ok +test predicate_bounds::tests::evaluate_bounds_and ... ok +test predicate_bounds::tests::evaluate_bounds_negative ... ok +test predicate_bounds::tests::evaluate_bounds_like ... ok +test predicate_bounds::tests::evaluate_bounds_not ... ok +test predicate_bounds::tests::evaluate_bounds_is ... ok +test ptr_eq::tests::test_ptr_eq_wrapper ... ok +test predicate_bounds::tests::evaluate_bounds_udf ... ok +test type_coercion::functions::tests::test_coerced_from_dictionary ... ok +test predicate_bounds::tests::evaluate_bounds_or ... ok +test type_coercion::functions::tests::test_coercible_dictionary ... ok +test type_coercion::functions::tests::test_coercible_nulls ... ok +test type_coercion::functions::tests::test_coercible_run_end_encoded ... ok +test type_coercion::functions::tests::test_fixed_list_wildcard_coerce ... ok +test type_coercion::functions::tests::test_get_valid_types_coercible_binary ... ok +test type_coercion::functions::tests::test_get_valid_types_array_and_element ... ok +test type_coercion::functions::tests::test_get_valid_types_element_and_array ... ok +test type_coercion::functions::tests::test_get_valid_types_array_and_array ... ok +test type_coercion::functions::tests::test_get_valid_types_fixed_size_arrays ... ok +test type_coercion::functions::tests::test_get_valid_types_length_check ... ok +test type_coercion::functions::tests::test_get_valid_types_numeric ... ok +test type_coercion::functions::tests::test_get_valid_types_one_of ... ok +test type_coercion::functions::tests::test_maybe_data_types ... ok +test type_coercion::functions::tests::test_nested_wildcard_fixed_size_lists ... ok +test type_coercion::functions::tests::test_string_conversion ... ok +test udaf::test::test_partial_eq ... ok +test udaf::test::test_partial_ord ... ok +test udf::tests::test_partial_eq_hash_and_partial_ord ... ok +test predicate_bounds::tests::evaluate_bounds_literal ... ok +test udf_eq::tests::test_eq_eq_wrapper ... ok +test udwf::test::test_partial_eq ... ok +test udwf::test::test_partial_ord ... ok +test utils::tests::test_can_hash ... ok +test utils::tests::avoid_generate_duplicate_sort_keys ... ok +test utils::tests::test_conjunction ... ok +test utils::tests::test_conjunction_empty ... ok +test utils::tests::test_collect_expr ... ok +test utils::tests::test_disjunction_empty ... ok +test utils::tests::test_disjunction ... ok +test utils::tests::test_generate_signature_error_msg_without_parameter_names ... ok +test utils::tests::test_group_window_expr_by_sort_keys_empty_case ... ok +test utils::tests::test_generate_signature_error_msg_with_parameter_names ... ok +test utils::tests::test_split_binary_owned ... ok +test utils::tests::test_group_window_expr_by_sort_keys_empty_window ... ok +test utils::tests::test_group_window_expr_by_sort_keys ... ok +test utils::tests::test_split_binary_owned_two ... ok +test utils::tests::test_split_binary_owned_different_op ... ok +test utils::tests::test_enumerate_grouping_sets ... ok +test utils::tests::test_split_conjunction ... ok +test utils::tests::test_split_conjunction_alias ... ok +test utils::tests::test_split_conjunction_owned ... ok +test utils::tests::test_split_conjunction_or ... ok +test utils::tests::test_split_conjunction_owned_alias ... ok +test utils::tests::test_split_conjunction_two ... ok +test utils::tests::test_split_conjunction_owned_two ... ok +test utils::tests::test_split_conjunction_owned_or ... ok +test var_provider::test::test_is_system_variables ... ok +test window_state::tests::test_default_window_frame_group_boundaries ... ok +test window_state::tests::test_ordered_window_frame_group_boundaries ... ok +test window_state::tests::test_unordered_window_frame_group_boundaries ... ok +test window_state::tests::test_window_frame_group_boundaries ... ok +test window_frame::tests::test_window_frame_bound_creation ... ok +test window_frame::tests::test_window_frame_creation ... ok +test window_state::tests::test_window_frame_group_boundaries_both_preceding ... ok +test window_state::tests::test_window_frame_group_boundaries_both_following ... ok + +test result: ok. 175 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s + + Running unittests src/lib.rs (target/debug/deps/datafusion_expr_common-24aed1122a3f7b09) + +running 135 tests +test casts::tests::test_try_cast_literal_to_timestamp ... ok +test casts::tests::test_try_cast_to_type_int_out_of_range ... ok +test casts::tests::test_error_conditions ... ok +test casts::tests::test_try_cast_to_fixed_size_binary ... ok +test casts::tests::test_binary_size_edge_cases ... ok +test casts::tests::test_try_cast_to_type_unsupported ... ok +test casts::tests::test_try_decimal_cast_out_of_range ... ok +test casts::tests::test_try_cast_to_string_type ... ok +test casts::tests::test_numeric_boundary_values ... ok +test casts::tests::test_type_support_functions ... ok +test casts::tests::test_try_cast_to_type_timestamps ... ok +test casts::tests::test_string_view ... ok +test columnar_value::tests::cast_date64_array_to_timestamp_overflow ... ok +test columnar_value::tests::into_array_of_size ... ok +test columnar_value::tests::cast_struct_by_field_name ... ok +test columnar_value::tests::cast_struct_missing_field_inserts_nulls ... ok +test casts::tests::test_decimal_precision_limits ... ok +test casts::tests::test_try_decimal_cast_in_range ... ok +test casts::tests::test_timestamp_overflow_scenarios ... ok +test columnar_value::tests::values_to_arrays ... ok +test casts::tests::test_dictionary_index_types ... ok +test columnar_value::tests::test_display_scalar ... ok +test interval_arithmetic::tests::and_test ... ok +test interval_arithmetic::tests::not_test ... ok +test interval_arithmetic::tests::gt_lt_test ... ok +test interval_arithmetic::tests::equal_test ... ok +test casts::tests::test_try_cast_to_dictionary_type ... ok +test interval_arithmetic::tests::nullable_interval_is_certainly_false ... ok +test interval_arithmetic::tests::gteq_lteq_test ... ok +test interval_arithmetic::tests::nullable_and_test ... ok +test interval_arithmetic::tests::intersect_test ... ok +test interval_arithmetic::tests::nullable_interval_contains_value ... ok +test interval_arithmetic::tests::nullable_interval_is_certainly_true ... ok +test interval_arithmetic::tests::nullable_interval_is_certainly_unknown ... ok +test casts::tests::test_try_cast_to_type_int_in_range ... ok +test columnar_value::tests::test_display_array ... ok +test interval_arithmetic::tests::nullable_interval_is_false ... ok +test interval_arithmetic::tests::nullable_interval_is_true ... ok +test interval_arithmetic::tests::nullable_interval_is_unknown ... ok +test interval_arithmetic::tests::nullable_not_test ... ok +test interval_arithmetic::tests::or_test ... ok +test interval_arithmetic::tests::test_and_or_with_normalized_boolean_intervals ... ok +test interval_arithmetic::tests::test_and_uncertain_boolean_intervals ... ok +test interval_arithmetic::tests::test_cardinality_of_intervals ... ok +test interval_arithmetic::tests::test_contains ... ok +test interval_arithmetic::tests::nullable_or_test ... ok +test interval_arithmetic::tests::test_interval_display ... ok +test columnar_value::tests::values_to_arrays_mixed_length_and_scalar - should panic ... ok +test columnar_value::tests::values_to_arrays_mixed_length - should panic ... ok +test interval_arithmetic::tests::test_is_superset ... ok +test interval_arithmetic::tests::test_make_unbounded ... ok +test interval_arithmetic::tests::test_contains_value ... ok +test interval_arithmetic::tests::test_new_interval ... ok +test interval_arithmetic::tests::test_null_boolean_interval ... ok +test interval_arithmetic::tests::test_or_uncertain_boolean_intervals ... ok +test interval_arithmetic::tests::test_overflow_handling ... ok +test interval_arithmetic::tests::test_uncertain_boolean_interval ... ok +test interval_arithmetic::tests::test_satisfy_comparison ... ok +test casts::tests::test_try_cast_to_type_nulls ... ok +test signature::tests::supports_zero_argument_tests ... ok +test interval_arithmetic::tests::union_test ... ok +test signature::tests::test_signature_nullary_with_empty_names ... ok +test interval_arithmetic::tests::test_next_prev_value ... ok +test interval_arithmetic::tests::test_sub ... ok +test interval_arithmetic::tests::test_add ... ok +test signature::tests::test_get_possible_types ... ok +test interval_arithmetic::tests::test_div ... ok +test interval_arithmetic::tests::test_add_intervals_lower_affected_f32 ... ok +test interval_arithmetic::tests::test_width_of_intervals ... ok +test interval_arithmetic::tests::test_mul ... ok +test signature::tests::test_signature_parameter_names_variadic ... ok +test signature::tests::test_signature_parameter_names_wrong_count ... ok +test signature::tests::test_signature_without_parameter_names ... ok +test signature::tests::test_to_string_repr_with_names_any ... ok +test signature::tests::test_to_string_repr_with_names_array_signature ... ok +test signature::tests::test_signature_numeric_with_parameter_names ... ok +test signature::tests::test_signature_with_parameter_names ... ok +test signature::tests::test_to_string_repr_with_names_coercible ... ok +test signature::tests::test_signature_uniform_with_parameter_names ... ok +test signature::tests::test_signature_parameter_names_duplicate ... ok +test signature::tests::test_to_string_repr_with_names_comparable_numeric_string ... ok +test signature::tests::test_to_string_repr_with_names_nullary ... ok +test signature::tests::test_to_string_repr_with_names_exact ... ok +test signature::tests::test_to_string_repr_with_names_one_of ... ok +test signature::tests::test_to_string_repr_with_names_partial ... ok +test signature::tests::test_to_string_repr_with_names_uniform ... ok +test signature::tests::test_to_string_repr_with_names_variadic_fallback ... ok +test signature::tests::test_type_signature_arity_any ... ok +test signature::tests::test_type_signature_arity_array_signature ... ok +test signature::tests::test_type_signature_arity_coercible ... ok +test signature::tests::test_type_signature_arity_comparable ... ok +test signature::tests::test_type_signature_arity_exact ... ok +test signature::tests::test_type_signature_arity_nullary ... ok +test signature::tests::test_type_signature_arity_numeric ... ok +test signature::tests::test_type_signature_arity_one_of_fixed ... ok +test signature::tests::test_type_signature_arity_one_of_variable ... ok +test signature::tests::test_type_signature_arity_string ... ok +test signature::tests::test_type_signature_arity_uniform ... ok +test signature::tests::test_type_signature_arity_user_defined ... ok +test signature::tests::test_type_signature_arity_variadic ... ok +test signature::tests::type_signature_partial_ord ... ok +test statistics::tests::bernoulli_dist_is_valid_test ... ok +test statistics::tests::gaussian_dist_is_valid_test ... ok +test statistics::tests::exponential_dist_is_valid_test ... ok +test statistics::tests::test_combine_bernoullis_unsupported_ops ... ok +test statistics::tests::test_calculate_generic_properties_gauss_gauss ... ok +test statistics::tests::test_combine_bernoullis_or_op ... ok +test statistics::tests::test_combine_gaussians_addition ... ok +test statistics::tests::generic_dist_is_valid_test ... ok +test statistics::tests::test_combine_bernoullis_and_op ... ok +test statistics::tests::test_calculate_generic_properties_uniform_uniform ... ok +test statistics::tests::test_combine_gaussians_subtraction ... ok +test statistics::tests::test_combine_gaussians_unsupported_ops ... ok +test statistics::tests::uniform_dist_is_valid_test ... ok +test statistics::tests::variance_extraction_test ... ok +test type_coercion::binary::tests::arithmetic::test_coercion_arithmetic_decimal ... ok +test type_coercion::binary::tests::arithmetic::test_coercion_arithmetic_decimal_cross_variant ... ok +test type_coercion::binary::tests::arithmetic::test_coercion_error ... ok +test statistics::tests::median_extraction_test ... ok +test type_coercion::binary::tests::arithmetic::test_decimal_mathematics_op_type ... ok +test type_coercion::binary::tests::arithmetic::test_decimal_precision_overflow_cross_variant ... ok +test statistics::tests::mean_extraction_test ... ok +test type_coercion::binary::tests::arithmetic::test_date_timestamp_arithmetic_error ... ok +test type_coercion::binary::tests::comparison::test_like_coercion ... ok +test type_coercion::binary::tests::comparison::test_list_coercion ... ok +test type_coercion::binary::tests::comparison::test_map_coercion ... ok +test type_coercion::binary::tests::dictionary::test_dictionary_type_coercion ... ok +test type_coercion::binary::tests::comparison::test_decimal_binary_comparison_coercion ... ok +test type_coercion::binary::tests::null_coercion::test_type_coercion_logical_op ... ok +test type_coercion::binary::tests::comparison::test_decimal_cross_variant_comparison_coercion ... ok +test type_coercion::binary::tests::run_end_encoded::test_ree_type_coercion ... ok +test type_coercion::binary::tests::arithmetic::test_type_coercion_arithmetic ... ok +test statistics::tests::test_compute_range_where_present ... ok +test type_coercion::binary::tests::comparison::test_type_coercion ... ok +test type_coercion::binary::tests::comparison::test_type_coercion_compare ... ok + +test result: ok. 135 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running unittests src/lib.rs (target/debug/deps/datafusion_ffi-accbef5738775b6e) + +running 74 tests +test execution::task_ctx_provider::tests::ffi_task_context_provider_clone ... ok +test execution::task_ctx_provider::tests::ffi_task_context_provider_out_of_scope ... ok +test insert_op::tests::test_all_round_trip_insert_ops ... ok +test execution::task_ctx_provider::tests::ffi_task_context_provider_round_trip ... ok +test physical_expr::sort::tests::ffi_sort_expr_round_trip ... ok +test physical_expr::partitioning::tests::round_trip_ffi_partitioning ... ok +test execution_plan::tests::test_ffi_execution_plan_local_bypass ... ok +test execution_plan::tests::test_ffi_execution_plan_children ... ok +test physical_expr::tests::ffi_physical_expr_display ... ok +test expr::columnar_value::tests::ffi_columnar_value_round_trip ... ok +test physical_expr::tests::ffi_physical_expr_bounds ... ok +test physical_expr::tests::ffi_physical_expr_constraints ... ok +test execution_plan::tests::test_round_trip_ffi_execution_plan ... ok +test physical_expr::tests::ffi_physical_expr_snapshots ... ok +test physical_expr::tests::ffi_physical_expr_hash ... ok +test physical_expr::tests::ffi_physical_expr_fields ... ok +test physical_expr::tests::ffi_physical_expr_volatility ... ok +test physical_expr::tests::ffi_physical_expr_properties ... ok +test physical_expr::tests::ffi_physical_expr_evaluate ... ok +test physical_expr::tests::ffi_physical_formatting ... ok +test physical_expr::tests::ffi_physical_expr_with_children ... ok +test physical_expr::tests::ffi_physical_expr_statistics ... ok +test physical_expr::tests::ffi_physical_expr_selection ... ok +test plan_properties::tests::test_round_trip_ffi_plan_properties ... ok +test plan_properties::tests::test_ffi_plan_properties_local_bypass ... ok +test proto::physical_extension_codec::tests::roundtrip_ffi_physical_extension_codec_exec_plan ... ok +test proto::logical_extension_codec::tests::roundtrip_ffi_logical_extension_codec_udaf ... ok +test catalog_provider_list::tests::test_round_trip_ffi_catalog_provider_list ... ok +test proto::logical_extension_codec::tests::roundtrip_ffi_logical_extension_codec_udwf ... ok +test proto::physical_extension_codec::tests::ffi_physical_extension_codec_local_bypass ... ok +test catalog_provider::tests::test_ffi_catalog_provider_local_bypass ... ok +test proto::logical_extension_codec::tests::ffi_logical_extension_codec_local_bypass ... ok +test catalog_provider_list::tests::test_ffi_catalog_provider_list_local_bypass ... ok +test proto::logical_extension_codec::tests::roundtrip_ffi_logical_extension_codec_udf ... ok +test catalog_provider::tests::test_round_trip_ffi_catalog_provider ... ok +test proto::physical_extension_codec::tests::roundtrip_ffi_physical_extension_codec_udf ... ok +test proto::physical_extension_codec::tests::roundtrip_ffi_physical_extension_codec_udaf ... ok +test schema_provider::tests::test_ffi_schema_provider_local_bypass ... ok +test proto::physical_extension_codec::tests::roundtrip_ffi_physical_extension_codec_udwf ... ok +test table_source::tests::round_trip_all_filter_pushdowns ... ok +test table_provider::tests::test_ffi_table_provider_local_bypass ... ok +test record_batch_stream::tests::test_round_trip_record_batch_stream ... ok +test proto::logical_extension_codec::tests::roundtrip_ffi_logical_extension_codec_table_provider ... ok +test record_batch_stream::tests::round_trip_record_batch_with_metadata ... ok +test schema_provider::tests::test_round_trip_ffi_schema_provider ... ok +test table_source::tests::test_round_all_trip_table_type ... ok +test udaf::groups_accumulator::tests::test_all_emit_to_round_trip ... ok +test udaf::accumulator::tests::test_ffi_accumulator_local_bypass ... ok +test udaf::accumulator_args::tests::test_round_trip_accumulator_args ... ok +test udaf::groups_accumulator::tests::test_ffi_groups_accumulator_local_bypass_inner ... ok +test udaf::tests::test_ffi_udaf_local_bypass ... ok +test execution::task_ctx::tests::ffi_task_ctx_round_trip ... ok +test udaf::tests::test_round_trip_all_order_sensitivities ... ok +test session::config::tests::test_round_trip_ffi_session_config ... ok +test udaf::tests::test_round_trip_udaf ... ok +test udaf::tests::test_round_trip_udaf_metadata ... ok +test udaf::tests::test_foreign_udaf_aliases ... ok +test udf::tests::test_ffi_udf_local_bypass ... ok +test udaf::tests::test_sliding_accumulator ... ok +test udf::tests::test_round_trip_scalar_udf ... ok +test udaf::tests::test_foreign_udaf_accumulator ... ok +test udaf::tests::test_beneficial_ordering ... ok +test udaf::groups_accumulator::tests::test_foreign_avg_accumulator ... ok +test udwf::partition_evaluator::tests::test_ffi_partition_evaluator_local_bypass_inner ... ok +test udwf::range::tests::test_round_trip_ffi_range ... ok +test udtf::tests::test_ffi_udtf_local_bypass ... ok +test volatility::tests::test_all_round_trip_volatility ... ok +test util::tests::test_conversion ... ok +test udaf::accumulator::tests::test_foreign_avg_accumulator ... ok +test udtf::tests::test_round_trip_udtf ... ok +test session::tests::test_ffi_session ... ok +test table_provider::tests::test_aggregation ... ok +test table_provider::tests::test_round_trip_ffi_table_provider_insert_into ... ok +test table_provider::tests::test_round_trip_ffi_table_provider_scan ... ok + +test result: ok. 74 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/ffi_catalog.rs (target/debug/deps/ffi_catalog-e0dd0d16dea16505) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/ffi_integration.rs (target/debug/deps/ffi_integration-803a55a2f8b73ed4) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/ffi_udaf.rs (target/debug/deps/ffi_udaf-a111a2be6f541bf1) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/ffi_udf.rs (target/debug/deps/ffi_udf-974d4141fb082e7a) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/ffi_udtf.rs (target/debug/deps/ffi_udtf-bf607237ed80e68f) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/ffi_udwf.rs (target/debug/deps/ffi_udwf-7c4f0240cdac3213) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_functions-136b4c35384ad15c) + +running 195 tests +test core::greatest::test::test_greatest_return_types_without_common_supertype_in_arg_type ... ok +test core::least::test::test_least_return_types_without_common_supertype_in_arg_type ... ok +test core::getfield::tests::test_get_field_utf8view_key ... ok +test core::nullif::tests::nullif_scalar ... ok +test core::union_tag::tests::union_scalar_empty ... ok +test core::union_tag::tests::union_scalar ... ok +test core::nullif::tests::nullif_int32 ... ok +test core::nullif::tests::nullif_literal_first ... ok +test core::nullif::tests::nullif_boolean ... ok +test core::nullif::tests::nullif_int32_non_nulls ... ok +test core::nullif::tests::nullif_string ... ok +test core::expr_ext::tests::test_field ... ok +test datetime::current_time::tests::test_current_time_timezone_offset ... ok +test datetime::date_bin::tests::test_date_bin_before_epoch ... ok +test datetime::date_bin::tests::test_date_bin_single ... ok +test core::overlay::tests::to_overlay ... ok +test core::union_extract::tests::test_scalar_value ... ok +test datetime::date_trunc::tests::date_trunc_test ... ok +test datetime::now::tests::now_func_default_matches_config ... ok +test core::version::test::test_version_udf ... ok +test datetime::from_unixtime::test::test_with_timezone ... ok +test datetime::from_unixtime::test::test_without_timezone ... ok +test datetime::make_time::tests::test_make_time ... ok +test datetime::to_date::tests::test_to_date_string_with_invalid_number ... ok +test datetime::date_bin::tests::test_date_bin_timezones ... ok +test datetime::date_trunc::tests::test_date_trunc_fine_granularity_timezones ... ok +test datetime::to_date::tests::test_to_date_string_with_valid_number ... ok +test datetime::to_date::tests::test_to_date_from_timestamp ... ok +test datetime::to_date::tests::test_to_date_multiple_format_strings ... ok +test datetime::date_trunc::tests::test_date_trunc_timezones ... ok +test datetime::date_bin::tests::test_date_bin ... ok +test datetime::date_trunc::tests::test_date_trunc_hour_timezones ... ok +test datetime::to_char::tests::test_array_array ... ok +test datetime::to_local_time::tests::test_adjust_to_local_time ... ok +test datetime::to_local_time::tests::test_timezone_with_daylight_savings ... ok +test datetime::to_local_time::tests::test_to_local_time_scalar ... ok +test datetime::to_timestamp::tests::string_to_timestamp_formatted_invalid ... ok +test datetime::to_timestamp::tests::string_to_timestamp_formatted ... ok +test datetime::to_local_time::tests::test_to_local_time_timezones_array ... ok +test datetime::to_date::tests::test_to_date_without_format ... ok +test datetime::to_timestamp::tests::string_to_timestamp_invalid_arguments ... ok +test datetime::to_timestamp::tests::test_decimal_to_nanoseconds_negative_scale ... ok +test datetime::to_char::tests::test_to_char ... ok +test datetime::to_timestamp::tests::to_timestamp_arrays_and_nulls ... ok +test datetime::to_date::tests::test_to_date_with_format ... ok +test datetime::to_timestamp::tests::to_timestamp_invalid_execution_timezone_behavior ... ok +test datetime::to_timestamp::tests::to_timestamp_invalid_input_type ... ok +test datetime::to_timestamp::tests::to_timestamp_with_formats_invalid_input_type ... ok +test datetime::to_timestamp::tests::to_timestamp_respects_execution_timezone ... ok +test datetime::to_timestamp::tests::to_timestamp_with_no_matching_formats ... ok +test datetime::to_timestamp::tests::test_to_timestamp_arg_validation ... ok +test datetime::to_timestamp::tests::to_timestamp_with_invalid_tz ... ok +test datetime::to_timestamp::tests::to_timestamp_with_formats_arrays_and_nulls ... ok +test datetime::to_timestamp::tests::to_timestamp_with_unparsable_data ... ok +test datetime::to_timestamp::tests::to_timestamp_formats_invalid_execution_timezone_behavior ... ok +test datetime::to_timestamp::tests::to_timestamp_formats_respects_execution_timezone ... ok +test datetime::to_timestamp::tests::test_no_tz ... ok +test encoding::inner::tests::test_estimate_byte_data_size ... ok +test math::cot::test::test_cot_f64 ... ok +test math::cot::test::test_cot_f32 ... ok +test math::cot::test::test_cot_scalar_f32 ... ok +test math::cot::test::test_cot_scalar_f64 ... ok +test math::cot::test::test_cot_scalar_null ... ok +test math::cot::test::test_cot_scalar_pi ... ok +test math::cot::test::test_cot_scalar_zero ... ok +test math::lcm::test::test_lcm_i64 ... ok +test math::log::tests::test_log_decimal128_invalid_base ... ok +test math::log::tests::test_log_decimal128_unary ... ok +test math::log::tests::test_log_decimal128_base_decimal ... ok +test math::log::tests::test_log_decimal256_large ... ok +test math::log::tests::test_log_decimal128_value_scale ... ok +test math::log::tests::test_log_decimal_native ... ok +test math::log::tests::test_log_decimal256_unary ... ok +test math::log::tests::test_log_f32 ... ok +test math::log::tests::test_log_f32_unary ... ok +test math::log::tests::test_log_f64 ... ok +test math::log::tests::test_log_f64_unary ... ok +test math::log::tests::test_log_invalid_value ... ok +test math::log::tests::test_log_output_ordering ... ok +test math::log::tests::test_log_scalar_decimal128 ... ok +test math::log::tests::test_log_scalar_decimal128_unary ... ok +test math::log::tests::test_log_invalid_base_type ... ok +test math::log::tests::test_log_scalar_f32 ... ok +test math::log::tests::test_log_scalar_f32_unary ... ok +test math::log::tests::test_log_scalar_f64 ... ok +test math::log::tests::test_log_scalar_f64_unary ... ok +test math::log::tests::test_log_simplify_errors ... ok +test math::log::tests::test_log_simplify_original ... ok +test math::monotonicity::tests::test_monotonicity_table ... ok +test math::nanvl::test::test_nanvl_f32 ... ok +test math::nanvl::test::test_nanvl_f64 ... ok +test math::power::tests::test_pow_decimal128_helper ... ok +test math::power::tests::test_pow_decimal_float_fallback ... ok +test math::round::test::test_round_f32_one_input ... ok +test math::round::test::test_round_f32_cast_fail ... ok +test math::round::test::test_round_f32 ... ok +test math::round::test::test_round_f64 ... ok +test math::round::test::test_round_f64_one_input ... ok +test math::signum::test::test_signum_f32 ... ok +test math::signum::test::test_signum_f64 ... ok +test math::trunc::test::test_truncate_32 ... ok +test math::trunc::test::test_truncate_64 ... ok +test math::tests::test_cases ... ok +test math::trunc::test::test_truncate_64_one_arg ... ok +test regex::regexplike::tests::test_unsupported_global_flag_regexp_like ... ok +test regex::regexpmatch::tests::test_unsupported_global_flag_regexp_match ... ok +test regex::regexplike::tests::test_case_sensitive_regexp_like_utf8view ... ok +test regex::regexpmatch::tests::test_case_sensitive_regexp_match ... ok +test regex::regexplike::tests::test_case_sensitive_regexp_like_utf8 ... ok +test regex::regexpreplace::tests::string_view_array ... ok +test regex::regexpreplace::tests::large_string_array ... ok +test regex::regexpreplace::tests::large_string_array_with_flags ... ok +test regex::regexpreplace::tests::string_array ... ok +test regex::regexpreplace::tests::string_array_with_flags ... ok +test regex::regexpreplace::tests::test_static_pattern_regexp_replace_early_abort_when_empty ... ok +test regex::regexpreplace::tests::test_static_pattern_regexp_replace_early_abort_flags ... ok +test regex::regexpreplace::tests::test_static_pattern_regexp_replace_early_abort ... ok +test regex::regexpreplace::tests::test_static_pattern_regexp_replace_pattern_error ... ok +test regex::regexpreplace::tests::string_view_array_with_flags ... ok +test regex::regexpreplace::tests::test_static_pattern_regexp_replace_with_null_buffers ... ok +test string::chr::tests::test_chr_empty ... ok +test regex::regexplike::tests::test_case_insensitive_regexp_like_utf8 ... ok +test regex::regexpreplace::tests::test_static_pattern_regexp_replace_with_sliced_null_buffer ... ok +test string::chr::tests::test_chr_error ... ok +test string::chr::tests::test_chr_normal ... ok +test regex::regexpmatch::tests::test_case_insensitive_regexp_match ... ok +test string::concat::tests::concat ... ok +test string::concat_ws::tests::concat_ws ... ok +test string::contains::test::test_contains_api ... ok +test regex::regexplike::tests::test_case_insensitive_regexp_like_utf8view ... ok +test string::ends_with::tests::test_array_array ... ok +test string::contains::test::test_contains_udf ... ok +test string::ends_with::tests::test_array_scalar_full_result ... ok +test string::ends_with::tests::test_array_scalar ... ok +test string::ends_with::tests::test_scalar_array ... ok +test string::levenshtein::tests::to_levenshtein ... ok +test string::lower::tests::lower_full_optimization ... ok +test string::lower::tests::lower_maybe_optimization ... ok +test string::concat_ws::tests::test_functions ... ok +test string::lower::tests::lower_partial_optimization ... ok +test string::concat::tests::test_functions ... ok +test string::ends_with::tests::test_scalar_scalar ... ok +test string::replace::tests::test_functions ... ok +test string::octet_length::tests::test_functions ... ok +test string::ascii::tests::test_functions ... ok +test string::btrim::tests::test_functions ... ok +test string::repeat::tests::test_functions ... ok +test string::starts_with::tests::test_array_array ... ok +test string::ltrim::tests::test_functions ... ok +test string::starts_with::tests::test_array_scalar ... ok +test string::split_part::tests::test_functions ... ok +test string::starts_with::tests::test_array_scalar_full_result ... ok +test string::rtrim::tests::test_functions ... ok +test string::to_hex::tests::to_hex_int16 ... ok +test string::starts_with::tests::test_scalar_array ... ok +test string::to_hex::tests::to_hex_int64 ... ok +test string::to_hex::tests::to_hex_int32 ... ok +test string::to_hex::tests::to_hex_int8 ... ok +test string::to_hex::tests::to_hex_large_signed ... ok +test string::starts_with::tests::test_scalar_scalar ... ok +test string::to_hex::tests::to_hex_large_unsigned ... ok +test string::to_hex::tests::to_hex_uint16 ... ok +test string::to_hex::tests::to_hex_uint32 ... ok +test string::to_hex::tests::to_hex_uint64 ... ok +test string::to_hex::tests::to_hex_uint8 ... ok +test string::upper::tests::upper_full_optimization ... ok +test string::upper::tests::upper_maybe_optimization ... ok +test string::upper::tests::upper_partial_optimization ... ok +test unicode::find_in_set::tests::test_find_in_set_with_scalar_args_2 ... ok +test unicode::find_in_set::tests::test_find_in_set_with_scalar_args ... ok +test regex::regexpinstr::tests::test_regexp_instr ... ok +test unicode::find_in_set::tests::test_find_in_set_with_scalar_args_3 ... ok +test unicode::find_in_set::tests::test_find_in_set_with_scalar_args_4 ... ok +test tests::test_no_duplicate_name ... ok +test unicode::character_length::tests::test_functions ... ok +test strings::tests::test_overflow_large_string_array_builder - should panic ... ok +test strings::tests::test_overflow_string_array_builder - should panic ... ok +test unicode::find_in_set::tests::test_functions ... ok +test unicode::initcap::tests::test_functions ... ok +test unicode::strpos::tests::nullable_return_type ... ok +test unicode::reverse::tests::test_functions ... ok +test unicode::right::tests::test_functions ... ok +test unicode::left::tests::test_functions ... ok +test utils::test::string_to_int_type ... ok +test utils::test::test_decimal128_to_i128 ... ok +test utils::test::test_calculate_binary_math_scalar_null ... ok +test unicode::translate::tests::test_functions ... ok +test unicode::substrindex::tests::test_functions ... ok +test utils::test::test_decimal32_to_i32 ... ok +test unicode::rpad::tests::test_functions ... ok +test utils::test::test_decimal64_to_i64 ... ok +test unicode::substr::tests::test_functions ... ok +test unicode::strpos::tests::test_strpos_functions ... ok +test unicode::lpad::tests::test_functions ... ok +test regex::regexpcount::tests::test_regexp_count ... ok + +test result: ok. 195 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running unittests src/lib.rs (target/debug/deps/datafusion_functions_aggregate-6ecd75eef50bde03) + +running 74 tests +test array_agg::tests::duplicates_distinct_sort_desc ... ok +test array_agg::tests::does_not_over_account_memory ... ok +test array_agg::tests::no_duplicates_distinct ... ok +test array_agg::tests::duplicates_distinct ... ok +test array_agg::tests::duplicates_distinct_sort_asc ... ok +test array_agg::tests::duplicates_on_second_batch_distinct ... ok +test array_agg::tests::all_nulls_on_both_batches_with_distinct ... ok +test array_agg::tests::all_nulls_on_first_batch_with_distinct ... ok +test array_agg::tests::does_not_over_account_memory_ordered ... ok +test array_agg::tests::duplicates_no_distinct ... ok +test array_agg::tests::no_duplicates_distinct_sort_asc ... ok +test array_agg::tests::does_not_over_account_memory_distinct ... ok +test array_agg::tests::no_duplicates_distinct_sort_asc_nulls_last ... ok +test array_agg::tests::no_duplicates_distinct_sort_asc_nulls_first ... ok +test array_agg::tests::no_duplicates_distinct_sort_desc_nulls_first ... ok +test array_agg::tests::no_duplicates_distinct_sort_desc ... ok +test array_agg::tests::no_duplicates_no_distinct ... ok +test array_agg::tests::no_duplicates_distinct_sort_desc_nulls_last ... ok +test count::tests::count_accumulator_nulls ... ok +test count::tests::count_accumulator_dictionary_with_null_values ... ok +test bit_and_or_xor::tests::test_bit_xor_accumulator ... ok +test count::tests::count_distinct_accumulator_dictionary_all_null_values ... ok +test count::tests::sliding_distinct_count_accumulator_basic ... ok +test count::tests::count_distinct_accumulator_dictionary_with_null_values ... ok +test count::tests::sliding_distinct_count_accumulator_retract ... ok +test first_last::tests::test_first_last_value_value ... ok +test first_last::tests::test_first_value_merge_with_is_set_nulls ... ok +test correlation::tests::test_accumulate_correlation_states ... ok +test first_last::tests::test_last_value_merge_with_is_set_nulls ... ok +test count::tests::sliding_distinct_count_accumulator_merge_states ... ok +test first_last::tests::test_first_last_state_after_merge ... ok +test count::tests::test_nested_dictionary ... ok +test hyperloglog::tests::test_empty ... ok +test hyperloglog::tests::test_empty_merge ... ok +test first_last::tests::test_last_group_acc ... ok +test first_last::tests::test_first_group_acc ... ok +test hyperloglog::tests::test_merge_overlapped ... ok +test first_last::tests::test_group_acc_size_of_ordering ... ok +test hyperloglog::tests::test_number_100 ... ok +test approx_percentile_cont::tests::test_combine_approx_percentile_accumulator ... ok +test first_last::tests::test_first_list_acc_size ... ok +test first_last::tests::test_last_list_acc_size ... ok +test hyperloglog::tests::test_one ... ok +test hyperloglog::tests::test_string ... ok +test hyperloglog::tests::test_number_1k ... ok +test hyperloglog::tests::test_u8 ... ok +test min_max::min_max_struct::tests::test_min_max_simple_struct ... ok +test min_max::min_max_struct::tests::test_min_max_multiple_groups ... ok +test min_max::tests::interval_min_max ... ok +test min_max::min_max_struct::tests::test_min_max_with_filter ... ok +test min_max::min_max_struct::tests::test_min_max_with_nulls ... ok +test min_max::min_max_struct::tests::test_min_max_nested_struct ... ok +test min_max::tests::float_min_max_with_nans ... ok +test min_max::tests::test_get_min_max_return_type_coerce_dictionary ... ok +test min_max::tests::test_min_max_coerce_types ... ok +test min_max::tests::test_min_max_dictionary ... ok +test stddev::tests::stddev_f64_merge_1 ... ok +test stddev::tests::stddev_f64_merge_2 ... ok +test min_max::tests::moving_max_tests ... ok +test string_agg::tests::duplicates_distinct_sort_asc ... ok +test string_agg::tests::duplicates_distinct_sort_desc ... ok +test string_agg::tests::duplicates_distinct ... ok +test string_agg::tests::no_duplicates_distinct ... ok +test string_agg::tests::duplicates_no_distinct ... ok +test string_agg::tests::no_duplicates_distinct_sort_asc ... ok +test string_agg::tests::no_duplicates_distinct_sort_desc ... ok +test string_agg::tests::no_duplicates_no_distinct ... ok +test min_max::tests::moving_min_tests ... ok +test variance::tests::test_groups_accumulator_merge_empty_states ... ok +test tests::test_no_duplicate_name ... ok +test hyperloglog::tests::test_number_10k ... ok +test hyperloglog::tests::test_number_100k ... ok +test hyperloglog::tests::test_repetition ... ok +test hyperloglog::tests::test_number_1m ... ok + +test result: ok. 74 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.11s + + Running unittests src/lib.rs (target/debug/deps/datafusion_functions_aggregate_common-0d6b5826c6c54d56) + +running 19 tests +test aggregate::groups_accumulator::accumulate::test::test_accumulate_multiple_with_nulls ... ok +test aggregate::groups_accumulator::accumulate::test::test_accumulate_multiple_with_nulls_and_filter ... ok +test aggregate::groups_accumulator::accumulate::test::test_accumulate_multiple_no_nulls_no_filter ... ok +test aggregate::groups_accumulator::accumulate::test::test_accumulate_multiple_with_filter ... ok +test tdigest::tests::test_identical_values_floating_point_precision ... ok +test aggregate::avg_distinct::decimal::tests::test_decimal64_distinct_avg_accumulator ... ok +test aggregate::avg_distinct::decimal::tests::test_decimal128_distinct_avg_accumulator ... ok +test aggregate::avg_distinct::decimal::tests::test_decimal256_distinct_avg_accumulator ... ok +test aggregate::avg_distinct::decimal::tests::test_decimal32_distinct_avg_accumulator ... ok +test tdigest::tests::test_size ... ok +test tdigest::tests::test_centroid_addition_regression ... ok +test tdigest::tests::test_int64_uniform ... ok +test aggregate::groups_accumulator::accumulate::test::accumulate ... ok +test merge_arrays::tests::test_merge_desc ... ok +test merge_arrays::tests::test_merge_asc ... ok +test tdigest::tests::test_merge_digests ... ok +test tdigest::tests::test_merge_unsorted_against_skewed_distro ... ok +test tdigest::tests::test_merge_unsorted_against_uniform_distro ... ok +test aggregate::groups_accumulator::accumulate::test::accumulate_fuzz ... ok + +test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.15s + + Running unittests src/lib.rs (target/debug/deps/datafusion_functions_nested-674390e0c4ec29e8) + +running 40 tests +test expr_ext::tests::test_index ... ok +test array_has::tests::test_simplify_array_has_with_null_list_to_null ... ok +test array_has::tests::test_simplify_array_has_with_null_to_null ... ok +test array_has::tests::test_array_has_complex_list_not_simplified ... ok +test array_has::tests::test_simplify_array_has_with_make_array_to_in_list ... ok +test expr_ext::tests::test_range ... ok +test extract::tests::test_array_slice_list_view_negative_stride ... ok +test extract::tests::test_array_slice_list_view_basic ... ok +test extract::tests::test_array_slice_list_view_non_monotonic_offsets ... ok +test extract::tests::test_array_slice_list_view_out_of_order ... ok +test array_has::tests::test_simplify_array_has_to_in_list ... ok +test extract::tests::test_array_element_return_type_fixed_size_list ... ok +test array_has::tests::test_array_has_list_null_haystack ... ok +test array_has::tests::test_array_has_list_empty_child ... ok +test extract::tests::test_array_slice_list_view_with_nulls ... ok +test map_values::tests::return_type_field ... ok +test map::tests::test_make_map_with_null_key_within_map_should_fail ... ok +test remove::tests::test_array_remove_all_nullability ... ok +test remove::tests::test_array_remove_n_nullability ... ok +test map::tests::test_make_map_with_fixed_size_list ... ok +test map::tests::test_make_map_with_large_list ... ok +test map::tests::test_make_map_with_null_maps ... ok +test remove::tests::test_array_remove_nullability ... ok +test reverse::tests::test_reverse_fixed_size_list_empty ... ok +test reverse::tests::test_reverse_list_view ... ok +test reverse::tests::test_reverse_large_list_view ... ok +test reverse::tests::test_reverse_fixed_size_list ... ok +test reverse::tests::test_reverse_list_view_all_nulls ... ok +test reverse::tests::test_reverse_list_view_empty ... ok +test remove::tests::test_array_remove_non_nullable ... ok +test remove::tests::test_array_remove_n_non_nullable ... ok +test remove::tests::test_array_remove_all_non_nullable ... ok +test reverse::tests::test_reverse_list_view_out_of_order ... ok +test remove::tests::test_array_remove_n_nullable ... ok +test remove::tests::test_array_remove_nullable ... ok +test remove::tests::test_array_remove_all_nullable ... ok +test reverse::tests::test_reverse_list_view_with_nulls ... ok +test utils::tests::test_align_array_dimensions ... ok +test tests::test_no_duplicate_name ... ok +test set_ops::tests::test_array_distinct_inner_nullability_result_type_match_return_type ... ok + +test result: ok. 40 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running unittests src/lib.rs (target/debug/deps/datafusion_functions_table-ea6cd5c262867890) + +running 1 test +test generate_series::generate_series_tests::test_generic_series_state_reset ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_functions_window-d000a4c55be9d172) + +running 14 tests +test lead_lag::tests::lead_lag_get_range ... ok +test rank::tests::test_dense_rank ... ok +test rank::tests::test_rank ... ok +test rank::tests::test_percent_rank ... ok +test cume_dist::tests::test_cume_dist ... ok +test row_number::tests::row_number_all_null ... ok +test row_number::tests::row_number_all_values ... ok +test nth_value::tests::last_value ... ok +test nth_value::tests::first_value ... ok +test nth_value::tests::nth_value_1 ... ok +test lead_lag::tests::test_lag_with_default ... ok +test nth_value::tests::nth_value_2 ... ok +test lead_lag::tests::test_lag_window_shift ... ok +test lead_lag::tests::test_lead_window_shift ... ok + +test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_functions_window_common-b17c1aae22defdbf) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/user_doc.rs (target/debug/deps/datafusion_macros-f6d0dee23e9cd04d) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_optimizer-cfb3c43d71aaa6b5) + +running 586 tests +test analyzer::type_coercion::test::agg_function_invalid_input_avg ... ok +test analyzer::type_coercion::test::agg_udaf_invalid_input ... ok +test analyzer::type_coercion::test::in_subquery_cast_all ... ok +test analyzer::type_coercion::test::in_subquery_cast_expr ... ok +test analyzer::type_coercion::test::between_case ... ok +test analyzer::type_coercion::test::concat_for_type_coercion ... ok +test analyzer::type_coercion::test::agg_udaf ... ok +test analyzer::type_coercion::test::between_null ... ok +test analyzer::type_coercion::test::binary_op_date32_eq_ts ... ok +test analyzer::type_coercion::test::binary_op_date32_op_interval ... ok +test analyzer::type_coercion::test::between_infer_cheap_type ... ok +test analyzer::type_coercion::test::agg_function_case ... ok +test analyzer::type_coercion::test::in_subquery_cast_subquery ... ok +test analyzer::type_coercion::test::scalar_function ... ok +test analyzer::type_coercion::test::scalar_udf_invalid_input ... ok +test analyzer::type_coercion::test::interval_plus_timestamp ... ok +test analyzer::type_coercion::test::scalar_udf ... ok +test analyzer::type_coercion::test::nested_case ... ok +test analyzer::type_coercion::test::inlist_case ... ok +test analyzer::type_coercion::test::simple_case ... ok +test analyzer::type_coercion::test::is_bool_for_type_coercion ... ok +test analyzer::type_coercion::test::like_for_type_coercion ... ok +test analyzer::type_coercion::test::tes_case_when_list ... ok +test analyzer::type_coercion::test::test_case_expression_coercion ... ok +test analyzer::type_coercion::test::coerce_utf8view_output ... ok +test analyzer::type_coercion::test::coerce_binaryview_output ... ok +test analyzer::type_coercion::test::test_map_with_diff_name ... ok +test analyzer::type_coercion::test::test_type_coercion_rewrite ... ok +test analyzer::type_coercion::test::test_then_else_list ... ok +test analyzer::type_coercion::test::timestamp_subtract_timestamp ... ok +test analyzer::type_coercion::test::unknown_for_type_coercion ... ok +test common_subexpr_eliminate::test::redundant_project_fields_join_input ... ok +test common_subexpr_eliminate::test::redundant_project_fields ... ok +test analyzer::type_coercion::test::test_coerce_union ... ok +test common_subexpr_eliminate::test::test_extract_expressions_from_col ... ok +test common_subexpr_eliminate::test::test_extract_expressions_from_grouping_set ... ok +test common_subexpr_eliminate::test::test_extract_expressions_from_grouping_set_with_identical_expr ... ok +test common_subexpr_eliminate::test::eliminated_subexpr_datatype ... ok +test common_subexpr_eliminate::test::cross_plans_subexpr ... ok +test common_subexpr_eliminate::test::subexpr_in_same_order ... ok +test common_subexpr_eliminate::test::filter_schema_changed ... ok +test common_subexpr_eliminate::test::nested_aliases ... ok +test common_subexpr_eliminate::test::subexpr_in_different_order ... ok +test common_subexpr_eliminate::test::aggregate_with_relations_and_dots ... ok +test common_subexpr_eliminate::test::test_alias_collision ... ok +test common_subexpr_eliminate::test::test_non_top_level_common_expression ... ok +test common_subexpr_eliminate::test::test_nested_common_expression ... ok +test common_subexpr_eliminate::test::test_normalize_bitset_and_expression ... ok +test common_subexpr_eliminate::test::test_normalize_bitset_xor_expression ... ok +test common_subexpr_eliminate::test::test_normalize_add_expression ... ok +test common_subexpr_eliminate::test::test_normalize_bitset_or_expression ... ok +test common_subexpr_eliminate::test::test_normalize_multi_expression ... ok +test common_subexpr_eliminate::test::test_normalize_ne_expression ... ok +test common_subexpr_eliminate::test::test_volatile ... ok +test common_subexpr_eliminate::test::test_normalize_eq_expression ... ok +test common_subexpr_eliminate::test::test_normalize_complex_expression ... ok +test common_subexpr_eliminate::test::test_volatile_short_circuits ... ok +test common_subexpr_eliminate::test::tpch_q1_simplified ... ok +test common_subexpr_eliminate::test::test_short_circuits ... ok +test decorrelate_predicate_subquery::tests::exists_distinct_expr_subquery ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_correlated ... ok +test decorrelate_predicate_subquery::tests::exists_distinct_subquery_with_literal ... ok +test decorrelate_predicate_subquery::tests::exists_correlated_unnest ... ok +test decorrelate_predicate_subquery::tests::exists_distinct_subquery ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_disjunction ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_expr_filter ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_no_cols ... ok +test common_subexpr_eliminate::test::test_normalize_inner_binary_expression ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_simple ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_where_less_than ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_where_not_eq ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_no_projection ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_project_expr ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_with_no_correlated_cols ... ok +test common_subexpr_eliminate::test::aggregate ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_should_support_additional_filters ... ok +test decorrelate_predicate_subquery::tests::exists_uncorrelated_unnest ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_with_same_table ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_with_subquery_filters ... ok +test decorrelate_predicate_subquery::tests::in_subquery_correlated ... ok +test decorrelate_predicate_subquery::tests::in_subquery_multi_col ... ok +test decorrelate_predicate_subquery::tests::exists_subquery_with_subquery_disjunction ... ok +test decorrelate_predicate_subquery::tests::in_subquery_both_side_expr ... ok +test decorrelate_predicate_subquery::tests::in_subquery_join_expr ... ok +test decorrelate_predicate_subquery::tests::in_subquery_no_projection ... ok +test decorrelate_predicate_subquery::tests::in_subquery_join_filter_and_inner_filter ... ok +test decorrelate_predicate_subquery::tests::in_subquery_simple ... ok +test decorrelate_predicate_subquery::tests::in_subquery_multiple ... ok +test decorrelate_predicate_subquery::tests::in_subquery_project_expr ... ok +test decorrelate_predicate_subquery::tests::in_subquery_nested ... ok +test decorrelate_predicate_subquery::tests::in_subquery_no_cols ... ok +test decorrelate_predicate_subquery::tests::in_subquery_multi_project_subquery_cols ... ok +test decorrelate_predicate_subquery::tests::in_subquery_where_not_eq ... ok +test decorrelate_predicate_subquery::tests::in_subquery_with_and_filters ... ok +test decorrelate_predicate_subquery::tests::in_subquery_where_less_than ... ok +test decorrelate_predicate_subquery::tests::in_subquery_with_same_table ... ok +test decorrelate_predicate_subquery::tests::in_subquery_with_subquery_disjunction ... ok +test decorrelate_predicate_subquery::tests::in_subquery_with_no_correlated_cols ... ok +test decorrelate_predicate_subquery::tests::not_exists_subquery_simple ... ok +test decorrelate_predicate_subquery::tests::not_in_subquery_simple ... ok +test decorrelate_predicate_subquery::tests::in_subquery_with_subquery_filters ... ok +test decorrelate_predicate_subquery::tests::multiple_subqueries ... ok +test decorrelate_predicate_subquery::tests::multiple_exists_subqueries ... ok +test decorrelate_predicate_subquery::tests::upper_case_ident ... ok +test decorrelate_predicate_subquery::tests::recursive_exists_subqueries ... ok +test decorrelate_predicate_subquery::tests::wrapped_not_in_subquery ... ok +test decorrelate_predicate_subquery::tests::should_support_additional_filters ... ok +test decorrelate_predicate_subquery::tests::wrapped_not_not_in_subquery ... ok +test decorrelate_predicate_subquery::tests::two_exists_subquery_with_outer_filter ... ok +test eliminate_cross_join::tests::eliminate_cross_join_multi_tables_1 ... ok +test eliminate_cross_join::tests::eliminate_cross_join_with_expr_and ... ok +test decorrelate_predicate_subquery::tests::recursive_subqueries ... ok +test eliminate_cross_join::tests::eliminate_cross_join_multi_tables_2 ... ok +test eliminate_cross_join::tests::eliminate_cross_join_multi_tables ... ok +test eliminate_cross_join::tests::eliminate_cross_not_possible ... ok +test eliminate_cross_join::tests::eliminate_cross_not_possible_simple ... ok +test eliminate_cross_join::tests::eliminate_cross_join_multi_tables_4 ... ok +test eliminate_cross_join::tests::eliminate_cross_join_multi_tables_3 ... ok +test eliminate_cross_join::tests::eliminate_cross_with_and ... ok +test decorrelate_predicate_subquery::tests::two_in_subquery_with_outer_filter ... ok +test eliminate_cross_join::tests::eliminate_cross_with_common_expr_or ... ok +test eliminate_cross_join::tests::eliminate_cross_with_common_expr_and ... ok +test eliminate_cross_join::tests::eliminate_cross_with_simple_and ... ok +test eliminate_cross_join::tests::eliminate_cross_join_multi_tables_5 ... ok +test eliminate_cross_join::tests::eliminate_cross_possible_nested_inner_join_with_filter ... ok +test eliminate_cross_join::tests::eliminate_cross_with_expr_or ... ok +test eliminate_cross_join::tests::eliminate_cross_with_simple_or ... ok +test eliminate_cross_join::tests::preserve_null_equality_setting ... ok +test eliminate_cross_join::tests::eliminate_cross_with_or ... ok +test eliminate_duplicated_expr::tests::eliminate_sort_exprs_with_options ... ok +test eliminate_cross_join::tests::reorder_join_to_eliminate_cross_join_multi_tables ... ok +test eliminate_filter::tests::filter_false ... ok +test eliminate_duplicated_expr::tests::eliminate_sort_expr ... ok +test eliminate_cross_join::tests::reorder_join_with_expr_key_multi_tables ... ok +test eliminate_filter::tests::filter_from_subquery ... ok +test eliminate_filter::tests::filter_null ... ok +test eliminate_filter::tests::filter_false_nested ... ok +test eliminate_filter::tests::filter_true ... ok +test eliminate_filter::tests::filter_true_nested ... ok +test eliminate_group_by_constant::tests::test_no_op_only_constant ... ok +test eliminate_join::tests::join_on_false ... ok +test eliminate_group_by_constant::tests::test_no_op_no_constants ... ok +test eliminate_group_by_constant::tests::test_no_op_volatile_scalar_fn_with_constant_arg ... ok +test eliminate_group_by_constant::tests::test_eliminate_constant_with_alias ... ok +test eliminate_limit::tests::limit_0_root ... ok +test eliminate_group_by_constant::tests::test_eliminate_constant ... ok +test eliminate_limit::tests::limit_0_nested ... ok +test eliminate_limit::tests::limit_fetch_with_ancestor_limit_skip ... ok +test eliminate_limit::tests::limit_join_with_ancestor_limit ... ok +test eliminate_group_by_constant::tests::test_eliminate_gby_literal ... ok +test eliminate_group_by_constant::tests::test_eliminate_scalar_fn_with_constant_arg ... ok +test eliminate_limit::tests::limit_with_ancestor_limit ... ok +test eliminate_limit::tests::limit_fetch_with_ancestor_limit_fetch ... ok +test eliminate_limit::tests::remove_zero_offset ... ok +test eliminate_outer_join::tests::eliminate_left_with_not_null ... ok +test eliminate_outer_join::tests::eliminate_full_with_type_cast ... ok +test eliminate_outer_join::tests::eliminate_full_with_and ... ok +test eliminate_outer_join::tests::eliminate_left_with_null ... ok +test eliminate_limit::tests::multi_limit_offset_sort_eliminate ... ok +test extract_equijoin_predicate::tests::join_with_alias_filter ... ok +test extract_equijoin_predicate::tests::join_with_expr_both_from_filter_and_keys ... ok +test eliminate_outer_join::tests::eliminate_right_with_or ... ok +test extract_equijoin_predicate::tests::join_with_multiple_table ... ok +test extract_equijoin_predicate::tests::join_with_only_column_equi_predicate ... ok +test extract_equijoin_predicate::tests::join_with_multiple_table_and_eq_filter ... ok +test extract_equijoin_predicate::tests::join_with_and_or_filter ... ok +test filter_null_join_keys::tests::both_side_nullable_expr_key ... ok +test filter_null_join_keys::tests::left_nullable ... ok +test filter_null_join_keys::tests::left_nullable_left_join ... ok +test filter_null_join_keys::tests::left_nullable_left_join_reordered ... ok +test filter_null_join_keys::tests::left_nullable_expr_key ... ok +test filter_null_join_keys::tests::left_nullable_on_condition_reversed ... ok +test extract_equijoin_predicate::tests::join_with_only_equi_expr_predicate ... ok +test extract_equijoin_predicate::tests::join_with_only_none_equi_predicate ... ok +test join_key_set::test::test_contains ... ok +test filter_null_join_keys::tests::right_nullable_expr_key ... ok +test join_key_set::test::test_insert_all ... ok +test join_key_set::test::test_insert ... ok +test join_key_set::test::test_insert_owned ... ok +test join_key_set::test::test_insert_all_owned ... ok +test filter_null_join_keys::tests::nested_join_multiple_filter_expr ... ok +test join_key_set::test::test_insert_intersection ... ok +test join_key_set::test::test_iterator ... ok +test filter_null_join_keys::tests::one_side_unqualified ... ok +test optimize_projections::tests::aggregate_no_group_by ... ok +test optimize_projections::tests::aggregate_group_by ... ok +test optimize_projections::tests::cast ... ok +test optimize_projections::tests::aggregate_group_by_with_table_alias ... ok +test optimize_projections::tests::aggregate_no_group_by_with_filter ... ok +test optimize_projections::tests::aggregate_with_periods ... ok +test optimize_projections::tests::aggregate_filter_pushdown ... ok +test optimize_projections::tests::merge_nested_alias ... ok +test optimize_projections::tests::join_schema_trim_full_join_column_projection ... ok +test optimize_projections::tests::merge_three_projection ... ok +test optimize_projections::tests::merge_alias ... ok +test optimize_projections::tests::join_schema_trim_using_join ... ok +test optimize_projections::tests::join_schema_trim_partial_join_column_projection ... ok +test optimize_projections::tests::pushdown_through_distinct ... ok +test optimize_projections::tests::merge_two_projection ... ok +test optimize_projections::tests::redundant_project ... ok +test optimize_projections::tests::reorder_scan ... ok +test optimize_projections::tests::table_full_filter_pushdown ... ok +test optimize_projections::tests::reorder_projection ... ok +test optimize_projections::tests::table_limit ... ok +test optimize_projections::tests::reorder_scan_projection ... ok +test optimize_projections::tests::table_scan_without_projection ... ok +test optimize_projections::tests::table_scan_projected_schema_non_qualified_relation ... ok +test optimize_projections::tests::noncontinuous_redundant_projection ... ok +test optimize_projections::tests::table_scan_projected_schema ... ok +test optimize_projections::tests::table_scan_with_literal_projection ... ok +test optimize_projections::tests::table_unused_projection ... ok +test optimize_projections::tests::test_double_optimization ... ok +test optimize_projections::tests::table_unused_aggregate ... ok +test optimize_projections::tests::test_between ... ok +test optimize_projections::tests::test_is_not_null ... ok +test optimize_projections::tests::test_case_merged ... ok +test optimize_projections::tests::test_is_not_true ... ok +test optimize_projections::tests::table_unused_column ... ok +test optimize_projections::tests::test_is_false ... ok +test optimize_projections::tests::test_derived_column ... ok +test optimize_projections::tests::test_is_true ... ok +test optimize_projections::tests::test_is_unknown ... ok +test optimize_projections::tests::test_neg_push_down ... ok +test optimize_projections::tests::test_is_not_false ... ok +test optimize_projections::tests::test_is_not_unknown ... ok +test optimize_projections::tests::test_not ... ok +test optimize_projections::tests::test_try_cast ... ok +test optimize_projections::tests::test_similar_to ... ok +test optimize_projections::tests::test_is_null ... ok +test optimize_projections::tests::test_user_defined_logical_plan_node ... ok +test optimize_projections::tests::test_nested_count ... ok +test optimize_projections::tests::test_user_defined_logical_plan_node2 ... ok +test optimize_projections::tests::test_user_defined_logical_plan_node3 ... ok +test optimize_unions::tests::eliminate_distinct_nothing ... ok +test optimize_projections::tests::test_user_defined_logical_plan_node4 ... ok +test optimize_unions::tests::eliminate_nested_distinct_union_with_distinct_table ... ok +test optimize_unions::tests::eliminate_nested_distinct_union ... ok +test optimize_unions::tests::eliminate_nested_union ... ok +test optimize_projections::tests::test_window ... ok +test optimize_unions::tests::eliminate_nested_distinct_union_with_projection ... ok +test optimize_unions::tests::eliminate_nested_distinct_union_with_type_cast_projection ... ok +test optimize_unions::tests::eliminate_one_union ... ok +test optimize_unions::tests::eliminate_nested_union_with_distinct_union ... ok +test optimizer::tests::generate_different_schema ... ok +test optimizer::tests::no_skip_failing_rule ... ok +test optimize_unions::tests::eliminate_nothing ... ok +test optimize_unions::tests::eliminate_nested_union_in_projection ... ok +test optimizer::tests::generate_same_schema_different_metadata ... ok +test optimize_unions::tests::eliminate_nested_union_with_projection ... ok +test optimize_unions::tests::eliminate_nested_union_with_type_cast_projection ... ok +test optimizer::tests::skip_failing_rule ... ok +test optimizer::tests::skip_generate_different_schema ... ok +test optimizer::tests::optimizer_detects_plan_equal_to_a_non_initial ... ok +test plan_signature::tests::node_number_for_some_plan ... ok +test optimizer::tests::optimizer_detects_plan_equal_to_the_initial ... ok +test propagate_empty_relation::tests::propagate_union_alias ... ok +test propagate_empty_relation::tests::cross_join_empty ... ok +test propagate_empty_relation::tests::propagate_empty ... ok +test propagate_empty_relation::tests::cooperate_with_eliminate_filter ... ok +test propagate_empty_relation::tests::propagate_union_all_empty ... ok +test propagate_empty_relation::tests::propagate_union_children_different_schema ... ok +test propagate_empty_relation::tests::propagate_union_empty ... ok +test propagate_empty_relation::tests::test_empty_with_non_empty ... ok +test propagate_empty_relation::tests::propagate_union_multi_empty ... ok +test push_down_filter::tests::alias ... ok +test push_down_filter::tests::double_limit ... ok +test push_down_filter::tests::complex_expression ... ok +test push_down_filter::tests::filter_2_breaks_limits ... ok +test push_down_filter::tests::filter_before_projection ... ok +test propagate_empty_relation::tests::test_join_empty_propagation_rules_noop ... ok +test push_down_filter::tests::filter_after_limit ... ok +test propagate_empty_relation::tests::test_join_empty_propagation_rules ... ok +test push_down_filter::tests::filter_complex_group_by ... ok +test push_down_filter::tests::filter_expression_keep_window ... ok +test push_down_filter::tests::filter_jump_2_plans ... ok +test push_down_filter::tests::filter_keep_agg ... ok +test push_down_filter::tests::filter_join_on_one_side ... ok +test push_down_filter::tests::filter_move_agg ... ok +test push_down_filter::tests::filter_join_on_common_dependent ... ok +test push_down_filter::tests::filter_move_partial_window ... ok +test push_down_filter::tests::filter_move_window ... ok +test push_down_filter::tests::complex_plan ... ok +test push_down_filter::tests::filter_no_columns ... ok +test push_down_filter::tests::filter_move_complex_window ... ok +test push_down_filter::tests::filter_move_agg_special ... ok +test push_down_filter::tests::filter_multiple_windows_disjoint_partitions ... ok +test push_down_filter::tests::filter_multiple_windows_common_partitions ... ok +test push_down_filter::tests::filter_order_keep_window ... ok +test push_down_filter::tests::filter_on_join_on_common_independent ... ok +test push_down_filter::tests::filter_with_table_provider_inexact ... ok +test push_down_filter::tests::filter_with_table_provider_exact ... ok +test push_down_filter::tests::filter_with_table_provider_unsupported ... ok +test push_down_filter::tests::filter_window_special_identifier ... ok +test push_down_filter::tests::filter_using_join_on_common_independent ... ok +test push_down_filter::tests::filter_with_table_provider_multiple_invocations ... ok +test push_down_filter::tests::full_join_on_with_filter ... ok +test push_down_filter::tests::filters_user_defined_node ... ok +test push_down_filter::tests::join_filter_removed ... ok +test push_down_filter::tests::join_filter_on_common ... ok +test push_down_filter::tests::join_filter_with_alias ... ok +test push_down_filter::tests::filter_using_left_join_on_common ... ok +test push_down_filter::tests::filter_using_right_join_on_common ... ok +test push_down_filter::tests::filter_using_left_join ... ok +test push_down_filter::tests::filter_using_right_join ... ok +test push_down_filter::tests::join_on_with_filter ... ok +test push_down_filter::tests::left_join_on_with_filter ... ok +test push_down_filter::tests::left_anti_join ... ok +test push_down_filter::tests::left_semi_join ... ok +test push_down_filter::tests::multi_combined_filter ... ok +test push_down_filter::tests::multi_combined_filter_exact ... ok +test push_down_filter::tests::left_semi_join_with_filters ... ok +test push_down_filter::tests::left_anti_join_with_filters ... ok +test push_down_filter::tests::multi_filter ... ok +test push_down_filter::tests::right_anti_join ... ok +test push_down_filter::tests::push_agg_need_replace_expr ... ok +test push_down_filter::tests::right_anti_join_with_filters ... ok +test push_down_filter::tests::right_semi_join_with_filters ... ok +test push_down_filter::tests::right_semi_join ... ok +test push_down_filter::tests::split_filter ... ok +test push_down_filter::tests::right_join_on_with_filter ... ok +test push_down_filter::tests::test_filter_with_alias ... ok +test push_down_filter::tests::test_filter_with_alias_2 ... ok +test push_down_filter::tests::test_propagation_of_optimized_inner_filters_with_projections ... ok +test push_down_filter::tests::test_in_filter_with_alias ... ok +test push_down_filter::tests::test_push_down_filter_to_user_defined_node ... ok +test push_down_filter::tests::test_in_filter_with_alias_2 ... ok +test push_down_filter::tests::test_in_subquery_with_alias ... ok +test push_down_filter::tests::test_filter_with_multi_alias ... ok +test push_down_filter::tests::test_project_same_name_different_qualifier ... ok +test push_down_filter::tests::test_push_down_volatile_mixed_table_scan ... ok +test push_down_filter::tests::test_push_down_volatile_mixed_unsupported_table_scan ... ok +test push_down_filter::tests::test_push_down_volatile_table_scan ... ok +test push_down_filter::tests::union_all ... ok +test push_down_filter::tests::test_union_different_schema ... ok +test push_down_filter::tests::test_push_down_volatile_function_in_aggregate ... ok +test push_down_limit::test::limit_doesnt_push_down_with_offset_aggregation ... ok +test push_down_filter::tests::two_filters_on_same_depth ... ok +test push_down_limit::test::limit_doesnt_push_down_aggregation ... ok +test push_down_limit::test::limit_push_down_sort ... ok +test push_down_filter::tests::test_push_down_volatile_function_in_join ... ok +test push_down_filter::tests::union_all_on_projection ... ok +test push_down_limit::test::limit_push_down_with_offset_take_smaller_limit ... ok +test push_down_limit::test::limit_push_down_sort_skip ... ok +test push_down_limit::test::limit_push_down_take_smaller_limit ... ok +test push_down_limit::test::limit_offset_should_not_push_down_with_offset_join ... ok +test push_down_limit::test::limit_push_down_cross_join ... ok +test push_down_limit::test::limit_offset_should_not_push_down_with_offset_sub_query ... ok +test push_down_filter::tests::test_crossjoin_with_or_clause ... ok +test push_down_limit::test::limit_pushdown_basic ... ok +test push_down_limit::test::limit_pushdown_disallowed_noop_plan ... ok +test push_down_limit::test::limit_pushdown_multiple_limits ... ok +test push_down_limit::test::limit_pushdown_with_offset_after_limit ... ok +test push_down_limit::test::limit_pushdown_with_offset_projection_table_provider ... ok +test push_down_limit::test::limit_pushdown_with_skip ... ok +test push_down_limit::test::limit_pushdown_projection_table_provider ... ok +test push_down_limit::test::limit_pushdown_multiple_inputs ... ok +test push_down_limit::test::limit_pushdown_should_not_pushdown_limit_with_offset_only ... ok +test push_down_limit::test::limit_should_push_down_right_outer_join ... ok +test push_down_limit::test::limit_pushdown_with_limit_after_offset ... ok +test push_down_filter::tests::user_defined_plan ... ok +test push_down_limit::test::limit_should_push_down_right_outer_join_with_offset ... ok +test push_down_limit::test::limit_should_push_down_with_offset_union ... ok +test push_down_limit::test::limit_should_push_down_left_outer_join_with_offset ... ok +test push_down_limit::test::limit_should_push_down_union ... ok +test push_down_limit::test::merge_limit_result_empty ... ok +test push_down_limit::test::offset_limit_should_not_push_down_with_offset_join ... ok +test push_down_limit::test::multi_stage_limit_recursive_to_deeper_limit ... ok +test push_down_limit::test::skip_great_than_fetch ... ok +test push_down_limit::test::push_down_subquery_alias ... ok +test replace_distinct_aggregate::tests::use_limit_1_when_no_columns ... ok +test replace_distinct_aggregate::tests::eliminate_redundant_distinct_simple ... ok +test replace_distinct_aggregate::tests::eliminate_redundant_distinct_pair ... ok +test replace_distinct_aggregate::tests::do_not_eliminate_distinct ... ok +test replace_distinct_aggregate::tests::do_not_eliminate_distinct_with_aggr ... ok +test push_down_limit::test::offset_limit_should_not_push_down_with_offset_sub_query ... ok +test push_down_limit::test::skip_limit_push_down_cross_join ... ok +test scalar_subquery_to_join::tests::scalar_subquery_multi_col ... ok +test scalar_subquery_to_join::tests::exists_subquery_correlated ... ok +test scalar_subquery_to_join::tests::scalar_subquery_no_projection ... ok +test scalar_subquery_to_join::tests::scalar_subquery_non_correlated_no_filters_with_non_equal_clause ... ok +test scalar_subquery_to_join::tests::scalar_subquery_additional_filters_with_non_equal_clause ... ok +test scalar_subquery_to_join::tests::scalar_subquery_disjunction ... ok +test scalar_subquery_to_join::tests::multiple_subqueries ... ok +test scalar_subquery_to_join::tests::scalar_subquery_additional_filters_with_equal_clause ... ok +test scalar_subquery_to_join::tests::scalar_subquery_non_correlated_no_filters_with_equal_clause ... ok +test scalar_subquery_to_join::tests::scalar_subquery_no_cols ... ok +test scalar_subquery_to_join::tests::correlated_scalar_subquery_in_between_clause ... ok +test scalar_subquery_to_join::tests::scalar_subquery_with_no_correlated_cols ... ok +test simplify_expressions::expr_simplifier::tests::just_simplifier_simplify_null_in_empty_inlist ... ok +test scalar_subquery_to_join::tests::scalar_subquery_where_not_eq ... ok +test scalar_subquery_to_join::tests::scalar_subquery_where_less_than ... ok +test scalar_subquery_to_join::tests::scalar_subquery_with_subquery_disjunction ... ok +test simplify_expressions::expr_simplifier::tests::simplify_and_constant_prop_with_case ... ok +test scalar_subquery_to_join::tests::scalar_subquery_project_expr ... ok +test scalar_subquery_to_join::tests::scalar_subquery_with_subquery_filters ... ok +test scalar_subquery_to_join::tests::uncorrelated_scalar_subquery_in_between_clause ... ok +test scalar_subquery_to_join::tests::recursive_subqueries ... ok +test simplify_expressions::expr_simplifier::tests::api_basic ... ok +test simplify_expressions::expr_simplifier::tests::basic_coercion ... ok +test simplify_expressions::expr_simplifier::tests::simplify_common_factor_conjunction_in_disjunction ... ok +test simplify_expressions::expr_simplifier::tests::simplify_and_constant_prop ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_between ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_case_when_any_true ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_bool_and ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_bool_or ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_eq_skip_nonboolean_type ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_is_not_known ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_eq ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_is_null ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_is_not_null ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_is_unknown ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_not_eq_skip_nonboolean_type ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_not_eq ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_case_when_then_else ... ok +test simplify_expressions::expr_simplifier::tests::simplify_fixed_size_binary_eq_lit ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_null_comparison ... ok +test scalar_subquery_to_join::tests::scalar_subquery_with_non_strong_project ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_case_when_first_true ... ok +test simplify_expressions::expr_simplifier::tests::simplify_expr_case_when_any_false ... ok +test simplify_expressions::expr_simplifier::tests::simplify_cast_literal ... ok +test simplify_expressions::expr_simplifier::tests::simplify_large_or ... ok +test simplify_expressions::expr_simplifier::tests::simplify_null_in_empty_inlist ... ok +test simplify_expressions::expr_simplifier::tests::test_expression_partial_simplify_2 ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_and_false ... ok +test simplify_expressions::expr_simplifier::tests::test_expression_partial_simplify_1 ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_and_not_self ... ok +test simplify_expressions::expr_simplifier::tests::test_optimize_volatile_conditions ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_and_or ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_and_or_non_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_and_by_zero ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_bitwise_shift_left_by_zero ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_and_same ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_and_by_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_or_by_zero ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_bitwise_shift_right_by_zero ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_or_and ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_and_true ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_shift_left_by_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_and_or ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_shift_right_by_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_xor_by_zero ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_bitwise_xor_by_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_composed_and ... ok +test simplify_expressions::expr_simplifier::tests::simplify_inlist ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_by_de_morgan_laws ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_composed_bitwise_and ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_canonicalize ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_composed_bitwise_or ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_divide_by_one ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_composed_bitwise_xor ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_divide_by_same ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_divide_by_zero ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_cycles ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_divide_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_divide_null_by_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_divide_zero_by_zero ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_eq_and_neq_with_different_literals ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_eq_not_self ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_modulo_by_one ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_modulo_by_one_non_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_modulo_by_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_modulo_by_zero_non_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_multiply_by_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_negated_and ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_multiply_by_one ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_null_and_false ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_or_and ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_or_false ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_or_and_non_null ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_multiply_by_zero ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_negated_bitwise_xor ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_or_not_self ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_negated_bitwise_and ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_negated_bitwise_or ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_or_true ... ok +test simplify_expressions::expr_simplifier::tests::simplify_literal_case_equality ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_or_same ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_simple_and ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_simple_bitwise_and ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_simple_bitwise_or ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_simple_bitwise_xor ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_simplify_eq_expr ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_simplify_arithmetic_expr ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_udaf ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_udwf ... ok +test simplify_expressions::expr_simplifier::tests::test_struct_cast_different_field_counts_not_foldable ... ok +test simplify_expressions::expr_simplifier::tests::test_struct_cast_different_names_same_count ... ok +test simplify_expressions::expr_simplifier::tests::test_struct_cast_empty_array_not_foldable ... ok +test simplify_expressions::expr_simplifier::tests::test_struct_cast_same_field_count_foldable ... ok +test simplify_expressions::simplify_exprs::tests::simplify_and_eval ... ok +test simplify_expressions::simplify_exprs::tests::simplify_is_null ... ok +test simplify_expressions::simplify_exprs::tests::simplify_is_not_null ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_between ... ok +test simplify_expressions::simplify_exprs::tests::cast_expr ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_binary ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_bool_and ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_bool_or ... ok +test simplify_expressions::simplify_exprs::tests::simplify_grouping_sets ... ok +test simplify_expressions::simplify_exprs::tests::simplify_equijoin_predicate ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_ilike ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_with_guarantee ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_exists ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_distinct_from ... ok +test simplify_expressions::expr_simplifier::tests::test_like_and_ilike ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_like ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_in ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_in_subquery ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not_distinct_from ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not_in_subquery ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not_exists ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_in_list ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not_in_list ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not_like ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not_between ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not_in ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_null ... ok +test simplify_expressions::simplify_exprs::tests::simplify_not_not_null ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_or_expr ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_filter_pushdown ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_not_eq_expr ... ok +test simplify_expressions::expr_simplifier::tests::test_simplify_regex ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_support_projection ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_eq_expr ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_not_expr ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_and_expr ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_table_full_filter_in_scan ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_support_aggregate ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_support_values ... ok +test simplify_expressions::simplify_literal::tests::test_parse_sql_integer_literal ... ok +test simplify_expressions::simplify_literal::tests::test_parse_sql_float_literal ... ok +test simplify_expressions::simplify_predicates::tests::test_extract_column_ignores_cast ... ok +test simplify_expressions::simplify_predicates::tests::test_simplify_predicates_direct_columns_only ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_with_or ... ok +test simplify_expressions::simplify_predicates::tests::test_simplify_predicates_with_cast ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_optimized_plan_with_composed_and ... ok +test simplify_expressions::udf_preimage::test::test_preimage_is_distinct_from_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_eq_rewrite_swapped ... ok +test simplify_expressions::udf_preimage::test::test_preimage_gteq_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_eq_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_no_preimage_no_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_lt_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_non_immutable_no_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_non_literal_rhs_no_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_gt_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_null_literal_no_rewrite_distinct_ops ... ok +test simplify_expressions::udf_preimage::test::test_preimage_lteq_rewrite ... ok +test simplify_expressions::unwrap_cast::tests::aliased ... ok +test simplify_expressions::udf_preimage::test::test_preimage_is_not_distinct_from_rewrite ... ok +test simplify_expressions::udf_preimage::test::test_preimage_noteq_rewrite ... ok +test simplify_expressions::simplify_exprs::tests::test_simplify_regex_special_cases ... ok +test simplify_expressions::unwrap_cast::tests::test_not_support_data_type ... ok +test simplify_expressions::unwrap_cast::tests::nested ... ok +test simplify_expressions::unwrap_cast::tests::test_not_unwrap_cast_comparison ... ok +test simplify_expressions::utils::tests::test_is_one ... ok +test simplify_expressions::unwrap_cast::tests::test_not_unwrap_cast_with_decimal_comparison ... ok +test simplify_expressions::utils::tests::test_is_zero ... ok +test simplify_expressions::unwrap_cast::tests::test_not_unwrap_list_cast_lit_comparison ... ok +test simplify_expressions::unwrap_cast::tests::test_unwrap_cast_comparison_string ... ok +test simplify_expressions::unwrap_cast::tests::test_unwrap_cast_with_timestamp_nanos ... ok +test simplify_expressions::unwrap_cast::tests::test_unwrap_cast_with_decimal_lit_comparison ... ok +test simplify_expressions::unwrap_cast::tests::test_unwrap_cast_comparison_large_string ... ok +test simplify_expressions::unwrap_cast::tests::test_unwrap_cast_comparison_unsigned ... ok +test simplify_expressions::unwrap_cast::tests::test_unwrap_list_cast_comparison ... ok +test single_distinct_to_groupby::tests::distinct_and_common ... ok +test single_distinct_to_groupby::tests::common_with_filter ... ok +test single_distinct_to_groupby::tests::common_with_order_by ... ok +test single_distinct_to_groupby::tests::distinct_with_filter ... ok +test simplify_expressions::unwrap_cast::tests::test_unwrap_cast_comparison ... ok +test single_distinct_to_groupby::tests::aggregate_with_filter_and_order_by ... ok +test single_distinct_to_groupby::tests::distinct_with_order_by ... ok +test single_distinct_to_groupby::tests::single_distinct_and_cube ... ok +test single_distinct_to_groupby::tests::single_distinct ... ok +test single_distinct_to_groupby::tests::not_exist_distinct ... ok +test single_distinct_to_groupby::tests::group_by_with_expr ... ok +test single_distinct_to_groupby::tests::one_distinct_and_two_common ... ok +test single_distinct_to_groupby::tests::single_distinct_and_grouping_set ... ok +test single_distinct_to_groupby::tests::one_field_two_distinct_and_groupby ... ok +test single_distinct_to_groupby::tests::single_distinct_and_groupby ... ok +test single_distinct_to_groupby::tests::one_distinct_and_one_common ... ok +test single_distinct_to_groupby::tests::two_distinct_and_groupby ... ok +test single_distinct_to_groupby::tests::single_distinct_expr ... ok +test single_distinct_to_groupby::tests::single_distinct_and_rollup ... ok +test single_distinct_to_groupby::tests::two_distinct_and_one_common ... ok +test utils::tests::expr_is_restrict_null_predicate ... ok + +test result: ok. 586 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s + + Running tests/optimizer_integration.rs (target/debug/deps/optimizer_integration-beeb18137b226cba) + +running 26 tests +test propagate_empty_relation ... ok +test eliminate_nested_filters ... ok +test eliminate_redundant_null_check_on_count ... ok +test join_keys_in_subquery_alias ... ok +test join_keys_in_subquery_alias_1 ... ok +test intersect ... ok +test distribute_by ... ok +test case_when_aggregate ... ok +test between_date32_plus_interval ... ok +test between_date64_plus_interval ... ok +test anti_join_with_join_filter ... ok +test case_when ... ok +test recursive_cte_projection_pushdown_baseline ... ok +test recursive_cte_projection_pushdown ... ok +test recursive_cte_with_aliased_self_reference ... ok +test recursive_cte_with_unused_columns ... ok +test unsigned_target_type ... ok +test select_wildcard_with_repeated_column_but_is_aliased ... ok +test recursive_cte_with_nested_subquery ... ok +test test_same_name_but_not_ambiguous ... ok +test semi_join_with_join_filter ... ok +test where_exists_distinct ... ok +test select_correlated_predicate_subquery_with_uppercase_ident ... ok +test push_down_filter_groupby_expr_contains_alias ... ok +test subquery_filter_with_cast ... ok +test test_propagate_empty_relation_inner_join_and_unions ... ok + +test result: ok. 26 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s + + Running unittests src/lib.rs (target/debug/deps/datafusion_physical_expr-26bb05a57bb69b80) + +running 1488 tests +test equivalence::class::tests::test_contains_any ... ok +test equivalence::class::tests::test_remove_redundant_entries_eq_group ... ok +test equivalence::class::tests::test_exprs_equal ... ok +test equivalence::class::tests::test_bridge_groups ... ok +test equivalence::class::tests::test_project_classes ... ok +test equivalence::class::tests::test_schema_normalize_expr_with_equivalence ... ok +test equivalence::properties::dependency::tests::project_equivalence_properties_test ... ok +test equivalence::ordering::tests::test_remove_redundant_entries_oeq_class ... ok +test equivalence::ordering::tests::test_ordering_satisfy ... ok +test equivalence::ordering::tests::test_ordering_satisfy_different_lengths ... ok +test equivalence::properties::dependency::tests::test_find_longest_permutation2 ... ok +test equivalence::properties::dependency::tests::test_normalize_ordering_equivalence_classes ... ok +test equivalence::properties::dependency::tests::test_normalize_sort_reqs ... ok +test equivalence::properties::dependency::tests::test_get_indices_of_matching_sort_exprs_with_order_eq ... ok +test equivalence::properties::dependency::tests::test_ordering_equivalence_with_non_lex_monotonic_multiply ... ok +test analysis::tests::test_analyze_invalid_boundary_exprs ... ok +test analysis::tests::test_analyze_empty_set_boundary_exprs ... ok +test equivalence::properties::dependency::tests::test_eliminate_redundant_monotonic_sorts ... ok +test equivalence::properties::dependency::tests::test_ordering_equivalence_with_concat_equality ... ok +test equivalence::properties::dependency::tests::test_requirements_compatible ... ok +test equivalence::properties::dependency::tests::test_ordering_equivalence_with_lex_monotonic_concat ... ok +test analysis::tests::test_analyze_boundary_exprs ... ok +test equivalence::properties::dependency::tests::test_schema_normalize_sort_requirement_with_equivalence ... ok +test equivalence::properties::dependency::tests::test_with_reorder_constant_filtering ... ok +test equivalence::properties::dependency::tests::test_with_reorder_comprehensive ... ok +test equivalence::properties::dependency::tests::test_with_reorder_incompatible_prefix ... ok +test equivalence::properties::dependency::tests::test_with_reorder_equivalent_expressions ... ok +test equivalence::properties::dependency::tests::project_equivalence_properties_test_multi ... ok +test equivalence::properties::dependency::tests::test_with_reorder_preserve_suffix ... ok +test equivalence::properties::joins::tests::test_get_updated_right_ordering_equivalence_properties ... ok +test equivalence::properties::dependency::tests::test_ordering_satisfaction_with_key_constraints ... ok +test equivalence::properties::union::tests::test_union_constant_value_preservation ... ok +test equivalence::properties::union::tests::test_constants_share_values ... ok +test equivalence::properties::dependency::tests::test_update_properties ... ok +test equivalence::properties::joins::tests::test_join_equivalence_properties ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_asc_desc_mismatch ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_common_constants ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_different_schemas ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_fill_gaps_non_symmetric ... ok +test equivalence::properties::dependency::tests::test_find_longest_permutation ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_fill_gaps ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_gap_fill_symmetric ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_gap_fill_and_common ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_prefix ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_fill_some_gaps ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_no_fill_gaps ... ok +test equivalence::tests::add_equal_conditions_test ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_constants_middle_desc ... ok +test equivalence::ordering::tests::test_ordering_satisfy_with_equivalence2 ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_multi_children_5 ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_multi_children_4 ... ok +test expressions::binary::tests::arithmetic_divide_zero ... ok +test expressions::binary::tests::and_with_nulls_op ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_multi_children_1 ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_multi_children_2 ... ok +test expressions::binary::tests::bitwise_shift_array_overflow_test ... ok +test equivalence::properties::union::tests::test_union_equivalence_properties_multi_children_3 ... ok +test expressions::binary::tests::bitwise_scalar_test ... ok +test expressions::binary::tests::bitwise_array_test ... ok +test expressions::binary::tests::bitwise_shift_array_test ... ok +test expressions::binary::tests::binary_comparison ... ok +test expressions::binary::tests::bitwise_shift_scalar_test ... ok +test expressions::binary::tests::binary_nested ... ok +test expressions::binary::tests::divide_op ... ok +test expressions::binary::tests::eq_op_bool ... ok +test expressions::binary::tests::gt_eq_op_bool ... ok +test expressions::binary::tests::divide_op_scalar ... ok +test expressions::binary::tests::eq_op_bool_scalar ... ok +test expressions::binary::tests::arithmetic_decimal_float_expr_test ... ok +test expressions::binary::tests::gt_eq_op_bool_scalar ... ok +test expressions::binary::tests::gt_op_bool ... ok +test expressions::binary::tests::arithmetic_decimal_expr_test ... ok +test expressions::binary::tests::gt_op_bool_scalar ... ok +test expressions::binary::tests::is_distinct_from_op_bool ... ok +test expressions::binary::tests::comparison_dict_decimal_scalar_expr_test ... ok +test expressions::binary::tests::lt_eq_op_bool ... ok +test expressions::binary::tests::is_not_distinct_from_op_bool ... ok +test expressions::binary::tests::divide_op_dict_decimal ... ok +test expressions::binary::tests::lt_eq_op_bool_scalar ... ok +test expressions::binary::tests::divide_op_dict_scalar ... ok +test expressions::binary::tests::lt_op_bool ... ok +test expressions::binary::tests::lt_op_bool_scalar ... ok +test expressions::binary::tests::divide_op_dict_scalar_decimal ... ok +test expressions::binary::tests::divide_op_dict ... ok +test expressions::binary::tests::minus_op ... ok +test expressions::binary::tests::minus_op_dict ... ok +test expressions::binary::tests::minus_op_dict_decimal ... ok +test expressions::binary::tests::minus_op_scalar ... ok +test expressions::binary::tests::minus_op_dict_scalar ... ok +test expressions::binary::tests::comparison_decimal_expr_test ... ok +test expressions::binary::tests::modulus_op ... ok +test expressions::binary::tests::minus_op_dict_scalar_decimal ... ok +test expressions::binary::tests::modulus_op_dict ... ok +test expressions::binary::tests::modules_op_dict_scalar ... ok +test expressions::binary::tests::modulus_op_scalar ... ok +test expressions::binary::tests::modulus_op_dict_decimal ... ok +test expressions::binary::tests::multiply_op ... ok +test expressions::binary::tests::modulus_op_dict_scalar_decimal ... ok +test expressions::binary::tests::multiply_op_dict ... ok +test expressions::binary::tests::multiply_op_dict_decimal ... ok +test expressions::binary::tests::multiply_op_scalar ... ok +test expressions::binary::tests::multiply_op_dict_scalar ... ok +test expressions::binary::tests::neq_op_bool ... ok +test expressions::binary::tests::multiply_op_dict_scalar_decimal ... ok +test expressions::binary::tests::or_with_nulls_op ... ok +test expressions::binary::tests::neq_op_bool_scalar ... ok +test expressions::binary::tests::plus_op ... ok +test expressions::binary::tests::plus_op_dict ... ok +test expressions::binary::tests::plus_op_dict_decimal ... ok +test expressions::binary::tests::plus_op_dict_scalar ... ok +test expressions::binary::tests::plus_op_scalar ... ok +test expressions::binary::tests::plus_op_dict_scalar_decimal ... ok +test expressions::binary::tests::test_add_with_overflow ... ok +test expressions::binary::tests::relatively_deeply_nested ... ok +test expressions::binary::tests::test_display_and_or_combo ... ok +test expressions::binary::tests::test_check_short_circuit ... ok +test expressions::binary::tests::test_evaluate_bounds_bool ... ok +test expressions::binary::tests::test_and_true_preselection_returns_lhs ... ok +test expressions::binary::tests::test_evaluate_bounds_int32 ... ok +test expressions::binary::tests::test_dictionary_type_to_array_coercion ... ok +test expressions::binary::tests::test_evaluate_statistics_bernoulli ... ok +test expressions::binary::tests::test_fmt_sql ... ok +test expressions::binary::tests::test_mul_with_overflow ... ok +test expressions::binary::tests::test_pre_selection_scatter ... ok +test expressions::binary::tests::test_evaluate_nested_type ... ok +test expressions::binary::tests::test_propagate_statistics_combination_of_range_holders_comparison ... ok +test expressions::binary::tests::test_subtract_with_overflow ... ok +test expressions::binary::tests::test_propagate_statistics_combination_of_range_holders_arithmetic ... ok +test expressions::case::literal_lookup_table::primitive_lookup_table::tests::should_implement_to_hashable_key_for_all_primitives ... ok +test expressions::binary::tests::test_to_result_type_array ... ok +test expressions::case::tests::case_test_incompatible ... ok +test expressions::binary::tests::test_evaluate_statistics_combination_of_range_holders ... ok +test expressions::case::tests::case_with_expr_boolean_dictionary ... ok +test expressions::case::tests::case_with_expr ... ok +test expressions::case::tests::case_eq ... ok +test expressions::case::tests::case_transform ... ok +test expressions::case::tests::case_expr_matches_and_nulls ... ok +test expressions::case::tests::case_with_expr_all_null_dictionary ... ok +test expressions::case::tests::case_with_expr_dictionary ... ok +test expressions::case::tests::case_with_expr_else ... ok +test expressions::case::tests::case_with_expr_divide_by_zero ... ok +test expressions::case::tests::case_with_matches_and_nulls ... ok +test expressions::case::tests::case_with_expr_when_null ... ok +test expressions::case::tests::case_with_scalar_predicate ... ok +test expressions::case::tests::case_with_expr_primitive_dictionary ... ok +test expressions::case::tests::case_without_expr ... ok +test expressions::case::tests::case_without_expr_divide_by_zero ... ok +test expressions::case::tests::case_without_expr_else ... ok +test expressions::case::tests::case_with_type_cast ... ok +test expressions::case::tests::test_case_expression_nullability_with_not_nullable_column ... ok +test expressions::case::tests::test_case_when_literal_lookup_f16_to_string_with_special_values ... ok +test expressions::case::tests::test_case_when_literal_lookup_f32_to_string_with_special_values ... ok +test expressions::case::tests::test_case_when_literal_lookup_f32_to_string_with_special_values_and_duplicate_cases ... ok +test expressions::case::tests::test_case_expression_nullability_with_nullable_column ... ok +test expressions::case::tests::test_case_when_literal_lookup_int32_to_string ... ok +test expressions::case::tests::test_case_when_literal_lookup_f64_to_string_with_special_values ... ok +test expressions::case::tests::test_expr_or_expr_specialization ... ok +test expressions::case::tests::test_case_when_literal_lookup_int32_to_string_with_duplicate_cases ... ok +test expressions::case::tests::test_decimal_with_non_default_precision_and_scale ... ok +test expressions::case::tests::test_case_when_literal_lookup_none_case_should_never_match ... ok +test expressions::case::tests::test_fmt_sql ... ok +test expressions::case::tests::test_column_or_null_specialization ... ok +test expressions::case::tests::test_timestamp_with_non_default_timezone ... ok +test expressions::cast::tests::invalid_cast ... ok +test expressions::cast::tests::test_cast_decimal ... ignored +test expressions::case::tests::test_when_null_and_some_cond_else_null ... ok +test expressions::case::tests::test_with_strings_to_int32 ... ok +test expressions::cast::tests::test_cast_decimal_to_decimal ... ok +test expressions::cast::tests::invalid_cast_with_options_error ... ok +test expressions::cast::tests::test_cast_i32_u32 ... ok +test expressions::cast::tests::test_cast_decimal_to_numeric ... ok +test expressions::cast::tests::test_cast_i64_t64 ... ok +test expressions::cast::tests::test_fmt_sql ... ok +test expressions::cast::tests::test_cast_i32_utf8 ... ok +test expressions::cast_column::tests::cast_primitive_array ... ok +test expressions::cast_column::tests::cast_nested_struct_array ... ok +test expressions::cast_column::tests::cast_struct_array_missing_child ... ok +test expressions::cast_column::tests::cast_struct_scalar ... ok +test expressions::column::test::out_of_bounds_data_type ... ok +test expressions::cast::tests::test_cast_numeric_to_decimal ... ok +test expressions::column::test::out_of_bounds_evaluate ... ok +test expressions::column::test::out_of_bounds_nullable ... ok +test expressions::binary::tests::test_similar_to ... ok +test expressions::dynamic_filters::test::test_hash_stable_after_update ... ok +test expressions::dynamic_filters::test::test_dynamic_filter_physical_expr_misbehaves_data_type_nullable ... ok +test expressions::dynamic_filters::test::test_hash_stable_for_same_instance ... ok +test expressions::dynamic_filters::test::test_identity_based_equality ... ok +test expressions::binary::tests::regex_with_nulls ... ok +test expressions::dynamic_filters::test::test_is_used ... ok +test expressions::dynamic_filters::test::test_snapshot ... ok +test expressions::dynamic_filters::test::test_with_new_children_independence ... ok +test expressions::dynamic_filters::test::test_wait_complete_already_complete ... ok +test expressions::in_list::tests::in_list_decimal ... ok +test expressions::in_list::tests::in_list_date_types ... ok +test expressions::in_list::tests::in_list_no_cols ... ok +test expressions::in_list::tests::in_list_bool ... ok +test expressions::in_list::tests::in_list_nested_struct ... ok +test expressions::in_list::tests::in_list_nullable ... ok +test expressions::in_list::tests::in_list_float64 ... ok +test expressions::in_list::tests::in_list_binary_types ... ok +test expressions::in_list::tests::in_list_struct_with_exprs_not_array ... ok +test expressions::in_list::tests::in_list_string_types ... ok +test expressions::in_list::tests::in_list_struct_with_nulls ... ok +test expressions::in_list::tests::in_list_struct_with_null_in_list ... ok +test expressions::in_list::tests::in_list_struct ... ok +test expressions::in_list::tests::test_in_list_dictionary_int32 ... ok +test expressions::in_list::tests::in_list_utf8_with_dict_types ... ok +test expressions::in_list::tests::in_list_int_types ... ok +test expressions::in_list::tests::test_in_list_comprehensive_null_handling ... ok +test expressions::in_list::tests::test_in_list_multiple_nulls_deduplication ... ok +test expressions::in_list::tests::test_in_list_null_handling_comprehensive ... ok +test expressions::in_list::tests::in_list_timestamp_types ... ok +test expressions::in_list::tests::test_in_list_null_type_both ... ok +test expressions::in_list::tests::test_in_list_null_type_column ... ok +test expressions::in_list::tests::test_in_list_null_type_list ... ok +test expressions::in_list::tests::test_in_list_with_only_nulls ... ok +test expressions::in_list::tests::test_in_list_esoteric_types ... ok +test expressions::in_list::tests::test_in_list_scalar_literal_cases ... ok +test expressions::is_not_null::tests::is_not_null_op ... ok +test expressions::is_not_null::tests::test_fmt_sql ... ok +test expressions::in_list::tests::test_not_in_null_handling_comprehensive ... ok +test expressions::is_not_null::tests::union_is_not_null_op ... ok +test expressions::in_list::tests::test_in_list_tuple_cases ... ok +test expressions::is_null::tests::dense_union_is_null ... ok +test expressions::is_null::tests::is_null_op ... ok +test expressions::is_null::tests::test_fmt_sql ... ok +test expressions::is_null::tests::sparse_union_is_null ... ok +test expressions::like::test::test_fmt_sql ... ok +test expressions::literal::tests::literal_i32 ... ok +test expressions::literal::tests::test_fmt_sql ... ok +test expressions::in_list::tests::test_in_list_dictionary_types ... ok +test expressions::negative::tests::test_evaluate_bounds ... ok +test expressions::negative::tests::test_evaluate_statistics ... ok +test expressions::negative::tests::array_negative_op ... ok +test expressions::negative::tests::test_fmt_sql ... ok +test expressions::negative::tests::test_negation_invalid_types ... ok +test expressions::negative::tests::test_negation_valid_types ... ok +test expressions::negative::tests::test_propagate_constraints ... ok +test expressions::negative::tests::test_propagate_statistics_range_holders ... ok +test expressions::not::tests::neg_op ... ok +test expressions::not::tests::test_evaluate_bounds ... ok +test expressions::not::tests::test_evaluate_statistics ... ok +test expressions::not::tests::test_fmt_sql ... ok +test expressions::try_cast::tests::invalid_cast ... ok +test expressions::try_cast::tests::test_cast_i32_utf8 ... ok +test expressions::try_cast::tests::test_cast_i32_u32 ... ok +test expressions::try_cast::tests::test_fmt_sql ... ok +test expressions::try_cast::tests::test_cast_i64_t64 ... ok +test expressions::try_cast::tests::test_try_cast_decimal_to_decimal ... ok +test expressions::try_cast::tests::test_try_cast_decimal_to_numeric ... ok +test expressions::try_cast::tests::test_try_cast_utf8_i32 ... ok +test expressions::try_cast::tests::test_try_cast_numeric_to_decimal ... ok +test intervals::cp_solver::tests::case_1_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test expressions::like::test::like_op ... ok +test intervals::cp_solver::tests::case_1_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_1_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_1_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test expressions::binary::tests::test_type_coercion ... ok +test intervals::cp_solver::tests::case_1_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_2_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_2_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_3_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_3_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test expressions::cast::tests::test_cast_decimal_to_decimal_overflow ... ok +test intervals::cp_solver::tests::case_4_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test expressions::in_list::tests::test_fmt_sql_1 ... ok +test expressions::in_list::tests::test_fmt_sql_2 ... ok +test expressions::in_list::tests::test_fmt_sql_3 ... ok +test expressions::in_list::tests::test_fmt_sql_4 ... ok +test intervals::cp_solver::tests::case_4_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test expressions::dynamic_filters::test::test_remap_children ... ok +test intervals::cp_solver::tests::case_4_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_4_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_4_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_f64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_f64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i32::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i32::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_02_1::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_02_1::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_01_0::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_01_0::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_03_2::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_03_2::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_05_4::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_04_3::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_04_3::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_06_12::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_05_4::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_06_12::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_07_32::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_08_314::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_07_32::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_08_314::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_10_123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_10_123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_09_3124::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_09_3124::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_11_125::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_12_211::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_13_215::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::test_gather_node_indices_cannot_provide ... ok +test intervals::cp_solver::tests::case_5_i64::seed_13_215::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::case_5_i64::seed_11_125::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::test_gather_node_indices_dont_remove ... ok +test intervals::cp_solver::tests::case_5_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::case_5_i64::seed_12_211::greater_op_1_Operator__Gt::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::test_propagate_certainly_false_and ... ok +test intervals::cp_solver::tests::test_propagate_comparison ... ok +test intervals::cp_solver::tests::case_5_i64::seed_14_4123::greater_op_1_Operator__Gt::less_op_2_Operator__LtEq ... ok +test intervals::cp_solver::tests::test_gather_node_indices_remove_one ... ok +test intervals::cp_solver::tests::test_gather_node_indices_remove ... ok +test intervals::cp_solver::tests::case_5_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_1_Operator__Lt ... ok +test intervals::cp_solver::tests::test_propagate_or ... ok +test intervals::cp_solver::tests::testing_not_possible ... ok +test intervals::cp_solver::tests::test_propagate_constraints_singleton_interval_at_right ... ok +test partitioning::tests::test_partitioning_current_superset ... ok +test partitioning::tests::partitioning_satisfy_distribution ... ok +test intervals::cp_solver::tests::test_propagate_constraints_column_interval_at_left ... ok +test partitioning::tests::test_partitioning_empty_hash ... ok +test partitioning::tests::test_partitioning_no_overlap ... ok +test partitioning::tests::test_partitioning_exact_match ... ok +test partitioning::tests::test_partitioning_partial_overlap ... ok +test partitioning::tests::test_partitioning_satisfy_by_subset ... ok +test intervals::cp_solver::tests::case_5_i64::seed_14_4123::greater_op_2_Operator__GtEq::less_op_2_Operator__LtEq ... ok +test partitioning::tests::test_partitioning_unknown ... ok +test physical_expr::tests::test_is_volatile_default_behavior ... ok +test physical_expr::tests::test_nested_expression_volatility ... ok +test physical_expr::tests::test_physical_exprs_contains ... ok +test physical_expr::tests::test_physical_exprs_equal ... ok +test physical_expr::tests::test_physical_exprs_set_equal ... ok +test projection::tests::test_column_indices_complex_expr ... ok +test projection::tests::test_column_indices_empty ... ok +test projection::tests::test_column_indices_multiple_columns ... ok +test projection::tests::test_column_indices_duplicates ... ok +test projection::tests::test_column_indices_unsorted ... ok +test planner::tests::test_create_physical_expr_scalar_input_output ... ok +test projection::tests::test_project_schema_empty ... ok +test projection::tests::test_project_schema_simple_columns ... ok +test projection::tests::test_project_schema_preserves_metadata ... ok +test projection::tests::test_project_statistics_columns_only ... ok +test projection::tests::test_project_statistics_empty ... ok +test projection::tests::test_merge_with_expressions ... ok +test projection::tests::test_merge_empty_projection_with_literal ... ok +test projection::tests::test_project_statistics_primitive_width_only ... ok +test projection::tests::test_project_schema_with_expressions ... ok +test projection::tests::test_merge_simple_columns ... ok +test projection::tests::test_project_statistics_with_complex_type_literal ... ok +test projection::tests::test_project_statistics_with_expressions ... ok +test projection::tests::test_projection_new ... ok +test projection::tests::test_projection_as_ref ... ok +test projection::tests::test_project_statistics_with_null_literal ... ok +test projection::tests::test_projection_from_vec ... ok +test projection::tests::test_stats_projection_column_with_primitive_width_only ... ok +test projection::tests::test_project_statistics_with_literal ... ok +test projection::tests::test_update_expr_with_complex_literal_expr ... ok +test projection::tests::test_stats_projection_columns_only ... ok +test projection::tests::try_merge_error ... ok +test projection::tests::test_update_expr_with_literal ... ok +test scalar_function::tests::test_scalar_function_volatile_node ... ok +test projection::tests::project_orderings3 ... ok +test simplifier::tests::test_demorgans_law_and ... ok +test simplifier::tests::test_demorgans_law_or ... ok +test projection::tests::project_orderings2 ... ok +test simplifier::tests::test_double_negation_elimination ... ok +test simplifier::tests::test_demorgans_with_comparison_simplification ... ok +test simplifier::tests::test_negate_comparison ... ok +test simplifier::tests::test_no_simplify_with_column ... ok +test simplifier::tests::test_not_literal ... ok +test simplifier::tests::test_nested_expression_simplification ... ok +test simplifier::tests::test_deeply_nested_not ... ok +test simplifier::tests::test_not_in_list ... ok +test simplifier::tests::test_double_not_in_list ... ok +test simplifier::tests::test_not_of_not_and_not ... ok +test simplifier::tests::test_simplify ... ok +test simplifier::tests::test_partial_simplify_with_column ... ok +test simplifier::tests::test_not_not_in_list ... ok +test simplifier::unwrap_cast::tests::test_complex_nested_expression ... ok +test simplifier::tests::test_simplify_deeply_nested_literals ... ok +test simplifier::tests::test_simplify_literal_binary_expr ... ok +test simplifier::tests::test_simplify_nested_literal_expr ... ok +test simplifier::unwrap_cast::tests::test_is_binary_expr_with_cast_and_literal ... ok +test simplifier::unwrap_cast::tests::test_no_unwrap_when_types_unsupported ... ok +test simplifier::unwrap_cast::tests::test_cast_that_cannot_be_unwrapped_overflow ... ok +test simplifier::unwrap_cast::tests::test_try_cast_unwrapping ... ok +test simplifier::unwrap_cast::tests::test_non_swappable_operator ... ok +test simplifier::tests::test_simplify_literal_comparison ... ok +test simplifier::unwrap_cast::tests::test_unwrap_cast_in_binary_comparison ... ok +test simplifier::unwrap_cast::tests::test_unwrap_cast_literal_on_left_side ... ok +test simplifier::tests::test_simplify_literal_string_concat ... ok +test simplifier::unwrap_cast::tests::test_unwrap_cast_with_decimal_types ... ok +test simplifier::unwrap_cast::tests::test_unwrap_cast_preserves_non_comparison_operators ... ok +test simplifier::unwrap_cast::tests::test_unwrap_cast_with_different_comparison_operators ... ok +test simplifier::unwrap_cast::tests::test_unwrap_cast_with_literal_on_left ... ok +test simplifier::unwrap_cast::tests::test_unwrap_cast_with_null_literals ... ok +test simplifier::unwrap_cast::tests::test_unwrap_cast_with_try_cast ... ok +test utils::guarantee::test::test_conjunction_and_disjunction_single_column ... ok +test statistics::stats_solver::tests::test_stats_integration ... ok +test utils::guarantee::test::test_literal ... ok +test utils::guarantee::test::test_conjunction_multi_column ... ok +test utils::guarantee::test::test_disjunction_single_column ... ok +test utils::guarantee::test::test_single ... ok +test utils::tests::test_build_dag ... ok +test utils::tests::test_collect_columns ... ok +test utils::guarantee::test::test_inlist_with_disjunction ... ok +test utils::tests::test_convert_to_expr ... ok +test utils::tests::test_get_indices_of_exprs_strict ... ok +test utils::guarantee::test::test_single_inlist ... ok +test window::window_expr::tests::test_is_row_ahead ... ok +test utils::guarantee::test::test_conjunction_single_column ... ok +test utils::tests::test_reassign_expr_columns_in_list ... ok +test utils::guarantee::test::test_disjunction_multi_column ... ok +test utils::guarantee::test::test_disjunction_and_conjunction_multi_column ... ok +test utils::guarantee::test::test_inlist_conjunction ... ok +test projection::tests::project_orderings ... ok +test planner::tests::test_deeply_nested_binary_expr ... ok + +test result: ok. 1487 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.10s + + Running unittests src/lib.rs (target/debug/deps/datafusion_physical_expr_adapter-2754017f2ea75d26) + +running 20 tests +test schema_rewriter::tests::test_replace_columns_with_literals_no_match ... ok +test schema_rewriter::tests::test_replace_columns_with_literals ... ok +test schema_rewriter::tests::test_rewrite_column_with_type_cast ... ok +test schema_rewriter::tests::test_non_nullable_missing_column_error ... ok +test schema_rewriter::tests::test_rewrite_missing_column_non_nullable_error ... ok +test schema_rewriter::tests::test_replace_columns_with_literals_nested_expr ... ok +test schema_rewriter::tests::test_batch_adapter_factory_reuse ... ok +test schema_rewriter::tests::test_rewrite_no_change_needed ... ok +test schema_rewriter::tests::test_batch_adapter_factory_identity ... ok +test schema_rewriter::tests::test_rewrite_missing_column_nullable ... ok +test schema_rewriter::tests::test_rewrite_missing_column ... ok +test schema_rewriter::tests::test_rewrite_multi_column_expr_with_type_cast ... ok +test schema_rewriter::tests::test_batch_adapter_factory_missing_column ... ok +test schema_rewriter::tests::test_try_rewrite_struct_field_access ... ok +test schema_rewriter::tests::test_rewrite_struct_compatible_cast ... ok +test schema_rewriter::tests::test_rewrite_struct_column_incompatible ... ok +test schema_rewriter::tests::test_batch_adapter_factory_with_struct ... ok +test schema_rewriter::tests::test_batch_adapter_factory_basic ... ok +test schema_rewriter::tests::test_adapt_batches ... ok +test schema_rewriter::tests::test_adapt_struct_batches ... ok + +test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running unittests src/lib.rs (target/debug/deps/datafusion_physical_expr_common-9401a757f5281603) + +running 60 tests +test binary_map::tests::test_mismatched_sizes - should panic ... ok +test binary_map::tests::string_set_basic_i32 ... ok +test binary_map::tests::string_set_empty ... ok +test binary_map::tests::string_set_non_utf8_32 ... ok +test binary_map::tests::string_set_one_null ... ok +test binary_map::tests::string_set_many_null ... ok +test binary_map::tests::test_mismatched_types - should panic ... ok +test binary_map::tests::string_set_non_utf8_64 ... ok +test binary_map::tests::test_large_binary_set ... ok +test binary_map::tests::string_set_basic_i64 ... ok +test binary_map::tests::test_binary_set ... ok +test binary_map::tests::test_map ... ok +test binary_view_map::tests::test_map ... ok +test binary_view_map::tests::string_view_set_one_null ... ok +test binary_view_map::tests::test_string_set_non_utf8 ... ok +test binary_view_map::tests::string_view_set_many_null ... ok +test binary_view_map::tests::string_view_set_empty ... ok +test binary_view_map::tests::test_binary_set ... ok +test metrics::tests::test_aggregate_by_name ... ok +test metrics::tests::test_display_labels_and_partition ... ok +test binary_view_map::tests::test_string_view_set_basic ... ok +test metrics::tests::test_bad_sum - should panic ... ok +test binary_map::tests::test_string_set_memory_usage ... ok +test metrics::tests::test_aggregate_partition_bad_sum - should panic ... ok +test metrics::tests::test_aggregate_partition_timestamps ... ok +test metrics::tests::test_display_labels_no_partition ... ok +test metrics::tests::test_display_no_labels_no_partition ... ok +test metrics::tests::test_display_no_labels_with_partition ... ok +test metrics::tests::test_output_rows ... ok +test metrics::tests::test_elapsed_compute ... ok +test metrics::tests::test_sum ... ok +test metrics::tests::test_sorted_for_display ... ok +test metrics::value::tests::test_custom_metric ... ok +test metrics::value::tests::test_custom_metric_with_mismatching_names ... ok +test metrics::value::tests::test_display_output_rows ... ok +test metrics::value::tests::test_display_ratio ... ok +test metrics::value::tests::test_display_spilled_bytes ... ok +test metrics::value::tests::test_display_time ... ok +test metrics::value::tests::test_display_timestamp ... ok +test metrics::value::tests::test_done_with_custom_endpoint ... ok +test metrics::value::tests::test_ratio_merge_strategy ... ok +test metrics::value::tests::test_human_readable_metric_formatting ... ok +test metrics::value::tests::test_ratio_set_methods ... ok +test metrics::value::tests::test_stop_with_custom_endpoint ... ok +test physical_expr::test::test_evaluate_selection_with_empty_record_batch_with_larger_false_selection ... ok +test physical_expr::test::test_evaluate_selection_with_empty_record_batch_with_larger_true_selection ... ok +test physical_expr::test::test_evaluate_selection_with_non_empty_record_batch_with_larger_true_selection ... ok +test physical_expr::test::test_evaluate_selection_with_non_empty_record_batch_with_larger_false_selection ... ok +test physical_expr::test::test_evaluate_selection_with_non_empty_record_batch_with_smaller_false_selection ... ok +test sort_expr::tests::test_is_reversed_sort_options ... ok +test physical_expr::test::test_evaluate_selection_with_non_empty_record_batch_with_smaller_true_selection ... ok +test physical_expr::test::test_evaluate_selection_with_non_empty_record_batch ... ok +test physical_expr::test::test_evaluate_selection_with_empty_record_batch ... ok +test binary_view_map::tests::test_string_set_memory_usage ... ok +test metrics::value::tests::test_timer_with_custom_instant ... ok +test utils::tests::scatter_int_end_with_false ... ok +test utils::tests::scatter_boolean ... ok +test utils::tests::scatter_with_null_mask ... ok +test utils::tests::scatter_int ... ok +test binary_map::tests::test_string_overflow - should panic ... ok + +test result: ok. 60 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.29s + + Running unittests src/lib.rs (target/debug/deps/datafusion_physical_optimizer-c8d2fb021ea9e782) + +running 20 tests +test filter_pushdown::tests::test_trace_to_original_index ... ok +test filter_pushdown::tests::test_filtered_vec_single_pass ... ok +test filter_pushdown::tests::test_filtered_vec_empty_filter ... ok +test filter_pushdown::tests::test_chain_filter_slice_complex_scenario ... ok +test filter_pushdown::tests::test_chain_filter_preserves_original_len ... ok +test filter_pushdown::tests::test_filtered_vec_all_pass ... ok +test filter_pushdown::tests::test_chain_filter_slice_different_types ... ok +test ensure_coop::tests::test_optimizer_is_idempotent ... ok +test ensure_coop::tests::test_multiple_leaf_nodes ... ok +test ensure_coop::tests::test_selective_wrapping ... ok +test projection_pushdown::test::no_computation_does_not_project ... ok +test projection_pushdown::test::simple_push_down ... ok +test projection_pushdown::test::complex_schema_push_down ... ok +test projection_pushdown::test::does_not_push_down_short_circuiting_expressions ... ok +test projection_pushdown::test::left_semi_join_projection ... ok +test ensure_coop::tests::test_eager_evaluation_resets_cooperative_context ... ok +test ensure_coop::tests::test_cooperative_exec_for_custom_exec ... ok +test projection_pushdown::test::does_not_push_down_volatile_functions ... ok +test projection_pushdown::test::push_down_with_existing_projections ... ok +test projection_pushdown::test::right_semi_join_projection ... ok + +test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s + + Running unittests src/lib.rs (target/debug/deps/datafusion_physical_plan-ca649109abb87851) + +running 1246 tests +test aggregates::group_values::multi_group_by::boolean::tests::test_nullable_boolean_equal_to ... ok +test aggregates::group_values::multi_group_by::boolean::tests::test_nullable_boolean_vectorized_operation_special_case ... ok +test aggregates::group_values::multi_group_by::boolean::tests::test_not_nullable_primitive_equal_to ... ok +test aggregates::group_values::multi_group_by::boolean::tests::test_nullable_primitive_vectorized_equal_to ... ok +test aggregates::group_values::multi_group_by::boolean::tests::test_not_nullable_primitive_vectorized_equal_to ... ok +test aggregates::group_values::multi_group_by::bytes::tests::test_byte_equal_to ... ok +test aggregates::group_values::multi_group_by::bytes::tests::test_byte_vectorized_operation_special_case ... ok +test aggregates::group_values::multi_group_by::bytes::tests::test_byte_vectorized_equal_to ... ok +test aggregates::group_values::multi_group_by::bytes_view::tests::test_byte_view_vectorized_operation_special_case ... ok +test aggregates::group_values::multi_group_by::bytes_view::tests::test_byte_view_append_val ... ok +test aggregates::group_values::multi_group_by::bytes_view::tests::test_byte_view_vectorized_equal_to ... ok +test aggregates::group_values::multi_group_by::bytes_view::tests::test_byte_view_equal_to ... ok +test aggregates::group_values::multi_group_by::bytes::tests::test_byte_take_n ... ok +test aggregates::group_values::multi_group_by::primitive::tests::test_not_nullable_primitive_vectorized_equal_to ... ok +test aggregates::group_values::multi_group_by::primitive::tests::test_not_nullable_primitive_equal_to ... ok +test aggregates::group_values::multi_group_by::bytes_view::tests::test_byte_view_take_n_partial_completed_nonzero_index ... ok +test aggregates::group_values::multi_group_by::primitive::tests::test_nullable_primitive_equal_to ... ok +test aggregates::group_values::multi_group_by::primitive::tests::test_nullable_primitive_vectorized_equal_to ... ok +test aggregates::group_values::multi_group_by::bytes_view::tests::test_byte_view_take_n ... ok +test aggregates::group_values::multi_group_by::primitive::tests::test_nullable_primitive_vectorized_operation_special_case ... ok +test aggregates::group_values::multi_group_by::tests::test_hashtable_modifying_in_emit_first_n ... ok +test aggregates::order::partial::tests::test_group_ordering_partial ... ok +test aggregates::group_values::multi_group_by::tests::test_intern_for_vectorized_group_values ... ok +test aggregates::row_hash::tests::test_skip_aggregation_probe_not_locked_until_skip ... ok +test aggregates::group_values::metrics::tests::test_groupby_metrics_final_mode ... ok +test aggregates::group_values::metrics::tests::test_groupby_metrics_partial_mode ... ok +test aggregates::row_hash::tests::test_double_emission_race_condition_bug ... ok +test aggregates::tests::group_exprs_nullable ... ok +test aggregates::group_values::multi_group_by::tests::test_emit_first_n_for_vectorized_group_values ... ok +test aggregates::tests::test_agg_exec_same_schema ... ok +test aggregates::tests::test_agg_exec_group_by_const ... ok +test aggregates::tests::test_agg_exec_struct_of_dicts ... ok +test aggregates::tests::test_aggregate_statistics_edge_cases ... ok +test aggregates::tests::aggregate_source_with_yielding ... ok +test aggregates::tests::aggregate_grouping_sets_source_not_yielding ... ok +test aggregates::tests::aggregate_source_not_yielding ... ok +test aggregates::tests::aggregate_grouping_sets_with_yielding_with_spill ... ok +test aggregates::tests::test_drop_cancel_without_groups ... ok +test aggregates::tests::test_drop_cancel_with_groups ... ok +test aggregates::tests::aggregate_grouping_sets_with_yielding ... ok +test aggregates::tests::aggregate_grouping_sets_source_not_yielding_with_spill ... ok +test aggregates::tests::test_get_finest_requirements ... ok +test aggregates::tests::test_skip_aggregation_after_first_batch ... ok +test aggregates::topk::hash_table::tests::should_emit_correct_type ... ok +test aggregates::tests::test_skip_aggregation_after_threshold ... ok +test aggregates::topk::heap::tests::should_find_worst ... ok +test aggregates::topk::heap::tests::should_drain ... ok +test aggregates::topk::hash_table::tests::should_resize_properly ... ok +test aggregates::topk::heap::tests::should_append ... ok +test aggregates::topk::heap::tests::should_heapify_down ... ok +test aggregates::topk::heap::tests::should_replace ... ok +test aggregates::topk::heap::tests::should_heapify_up ... ok +test aggregates::tests::test_oom ... ok +test aggregates::topk::priority_map::tests::should_accept_higher_group ... ok +test aggregates::topk::priority_map::tests::should_accept_higher_for_group ... ok +test aggregates::topk::priority_map::tests::should_append ... ok +test aggregates::topk::priority_map::tests::should_accept_lower_for_group ... ok +test aggregates::topk::priority_map::tests::should_append_with_utf8view ... ok +test aggregates::topk::priority_map::tests::should_append_with_large_utf8 ... ok +test aggregates::topk::priority_map::tests::should_accept_lower_group ... ok +test aggregates::topk::priority_map::tests::should_handle_null_ids ... ok +test aggregates::topk::priority_map::tests::should_ignore_higher_group ... ok +test aggregates::topk::priority_map::tests::should_ignore_higher_same_group ... ok +test aggregates::topk::priority_map::tests::should_ignore_lower_group ... ok +test aggregates::topk::priority_map::tests::should_ignore_lower_same_group ... ok +test aggregates::topk::priority_map::tests::should_track_lexicographic_max_utf8_value_desc ... ok +test aggregates::topk::priority_map::tests::should_track_large_utf8_values ... ok +test aggregates::topk::priority_map::tests::should_track_lexicographic_min_utf8_value ... ok +test aggregates::tests::test_grouped_aggregation_respects_memory_limit ... ok +test async_func::tests::test_async_fn_with_coalescing ... ok +test aggregates::topk::priority_map::tests::should_track_utf8_view_values ... ok +test coalesce::tests::test_coalesce_single_large_batch_over_fetch ... ok +test aggregates::tests::test_order_is_retained_when_spilling ... ok +test aggregates::tests::aggregate_source_not_yielding_with_spill ... ok +test coalesce::tests::test_coalesce_with_fetch_less_target_batch_size ... ok +test aggregates::tests::aggregate_source_with_yielding_with_spill ... ok +test coalesce_partitions::tests::merge ... ok +test coalesce::tests::test_coalesce ... ok +test coalesce::tests::test_coalesce_with_fetch_less_than_input_size ... ok +test coalesce_partitions::tests::test_multi_partition_fetch_exact_match ... ok +test coalesce_partitions::tests::test_multi_partition_with_fetch_one ... ok +test coalesce::tests::test_coalesce_with_fetch_less_than_target_and_no_remaining_rows ... ok +test aggregates::tests::test_aggregate_with_spill_if_necessary ... ok +test coalesce::tests::test_coalesce_with_fetch_larger_than_input_size ... ok +test coalesce_partitions::tests::test_single_partition_with_fetch ... ok +test coalesce_partitions::tests::test_single_partition_without_fetch ... ok +test coalesce_partitions::tests::test_single_partition_fetch_larger_than_batch ... ok +test column_rewriter::tests::test_circular_reference_prevention ... ok +test column_rewriter::tests::test_nested_column_replacement_with_jump ... ok +test column_rewriter::tests::test_multiple_replacements_in_same_expression ... ok +test column_rewriter::tests::test_jump_with_complex_replacement_expression ... ok +test column_rewriter::tests::test_simple_column_replacement_with_jump ... ok +test column_rewriter::tests::test_unmapped_columns_detection ... ok +test common::tests::test_compute_record_batch_statistics_empty ... ok +test common::tests::test_compute_record_batch_statistics ... ok +test common::tests::test_compute_record_batch_statistics_null ... ok +test display::tests::test_display_when_stats_error_with_no_show_stats ... ok +test coop::tests::yield_less_than_threshold ... ok +test display::tests::test_display_when_stats_ok_with_show_stats ... ok +test coop::tests::yield_equal_to_threshold ... ok +test display::tests::test_display_when_stats_ok_with_no_show_stats ... ok +test display::tests::test_display_when_stats_panic_with_no_show_stats ... ok +test coop::tests::yield_more_than_threshold ... ok +test empty::tests::empty ... ok +test empty::tests::invalid_execute ... ok +test display::tests::test_display_when_stats_error_with_show_stats - should panic ... ok +test execution_plan::tests::test_check_not_null_constraints_accept_non_null ... ok +test empty::tests::with_new_children ... ok +test execution_plan::tests::test_check_not_null_constraints_on_null_type ... ok +test display::tests::test_display_when_stats_panic_with_show_stats - should panic ... ok +test execution_plan::tests::test_check_not_null_constraints_reject_null ... ok +test execution_plan::tests::test_check_not_null_constraints_with_dictionary_array_with_null ... ok +test execution_plan::tests::test_check_not_null_constraints_with_dictionary_masking_null ... ok +test execution_plan::tests::test_execution_plan_name ... ok +test execution_plan::tests::test_check_not_null_constraints_with_run_end_array ... ok +test coalesce_partitions::tests::test_panic - should panic ... ok +test filter::tests::test_builder_invalid_projection ... ok +test filter::tests::test_builder_predicate_validation ... ok +test filter::tests::collect_columns_predicates ... ok +test filter::tests::test_builder_projection_composition_none_clears ... ok +test filter::tests::test_builder_projection_composition ... ok +test filter::tests::test_builder_statistics_with_projection ... ok +test filter::tests::test_builder_without_projection ... ok +test filter::tests::test_custom_filter_selectivity ... ok +test filter::tests::test_builder_with_projection ... ok +test filter::tests::test_filter_statistics_basic_expr ... ok +test aggregates::tests::run_first_last_multi_partitions ... ok +test filter::tests::test_equivalence_properties_union_type ... ok +test filter::tests::test_builder_vs_with_projection ... ok +test filter::tests::test_filter_statistics_column_level_nested ... ok +test filter::tests::test_filter_statistics_full_selective ... ok +test filter::tests::test_empty_input_statistics ... ok +test filter::tests::test_filter_statistics_column_level_nested_multiple ... ok +test filter::tests::test_filter_statistics_zero_selective ... ok +test filter::tests::test_filter_statistics_multiple_columns ... ok +test joins::array_map::tests::test_array_map_i64_with_negative_and_positive_numbers ... ok +test filter::tests::test_validation_filter_selectivity ... ok +test filter::tests::test_statistics_with_constant_column ... ok +test filter::tests::test_filter_statistics_more_inputs ... ok +test joins::array_map::tests::test_array_map_limit_offset_duplicate_elements ... ok +test joins::array_map::tests::test_array_map_with_limit_and_misses ... ok +test joins::array_map::tests::test_array_map_with_build_duplicates_and_misses ... ok +test filter::tests::test_filter_statistics_when_input_stats_missing ... ok +test joins::cross_join::tests::test_overallocation ... ok +test joins::cross_join::tests::test_stats_cartesian_product_with_unknown_size ... ok +test joins::cross_join::tests::test_stats_cartesian_product ... ok +test joins::cross_join::tests::test_join ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_date32 ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_empty_right::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_multi_batch::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_one::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_full_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_randomly_ordered ... ok +test joins::hash_join::exec::tests::join_inner_one_no_shared_column_names ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left_randomly_ordered ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_left::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_one_two_parts_right::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_two::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test analyze::tests::test_drop_cancel ... ok +test joins::hash_join::exec::tests::join_inner_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test coalesce_partitions::tests::test_drop_cancel ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_anti_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_empty_right::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_mark::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_multi_batch::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_one::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_left_semi_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_left_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_on_struct ... ok +test joins::hash_join::exec::tests::join_on_struct_with_nulls ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_anti_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_mark::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_one::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_semi_with_filter::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_with_hash_collisions_64 ... ok +test joins::hash_join::exec::tests::join_with_hash_collisions_u32 ... ok +test joins::hash_join::exec::tests::join_with_duplicated_column_names ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::join_right_with_filter::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::join_with_error_right ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_inner_one::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_mark::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_left_one::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_overallocation ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_mark::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::partitioned_join_right_one::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::single_partition_join_overallocation ... ok +test joins::hash_join::exec::tests::test_hash_join_marks_filter_complete_empty_build_side ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_build_null::batch_size_1_8192 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_build_null::batch_size_3_5 ... ok +test joins::hash_join::exec::tests::test_hash_join_marks_filter_complete ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_build_null::batch_size_2_10 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_build_null::batch_size_5_1 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_no_nulls::batch_size_1_8192 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_no_nulls::batch_size_2_10 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_no_nulls::batch_size_3_5 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_probe_null::batch_size_1_8192 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_probe_null::batch_size_4_2 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_probe_null::batch_size_3_5 ... ok +test joins::hash_join::exec::tests::test_null_aware_validation_multi_column ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_no_nulls::batch_size_5_1 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_build_null::batch_size_4_2 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_no_nulls::batch_size_4_2 ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_probe_null::batch_size_2_10 ... ok +test joins::hash_join::exec::tests::test_null_aware_validation_wrong_join_type ... ok +test joins::hash_join::exec::tests::test_null_aware_anti_join_probe_null::batch_size_5_1 ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::test_perfect_hash_join_with_negative_numbers ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_have_nulls ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_1_8192::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_2_10::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_nothing_build_probe_all_have_nulls::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_1_8192::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_3_5::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_4_2::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_5_1::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_4_2::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::inlist_builder::tests::test_build_multi_column_inlist ... ok +test joins::hash_join::inlist_builder::tests::test_build_single_column_inlist_array ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_expr_eq_different_columns ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_expr_eq_different_description ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_2_10::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_expr_eq_different_seeds ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_expr_eq_same ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_3_5::use_perfect_hash_join_as_possible_1_true ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_table_lookup_expr_eq_different_columns ... ok +test joins::hash_join::exec::tests::test_phj_null_equals_null_build_no_nulls_probe_has_nulls::batch_size_5_1::use_perfect_hash_join_as_possible_2_false ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_expr_hash_consistency ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_table_lookup_expr_eq_different_description ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_table_lookup_expr_eq_different_hash_map ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_table_lookup_expr_eq_same ... ok +test joins::hash_join::partitioned_hash_eval::tests::test_hash_table_lookup_expr_hash_consistency ... ok +test joins::join_hash_map::tests::test_contain_hashes ... ok +test joins::nested_loop_join::tests::join_has_correct_stats ... ok +test joins::nested_loop_join::tests::join_inner_with_filter::batch_size_2_2 ... ok +test joins::nested_loop_join::tests::join_inner_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_full_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_full_with_filter::batch_size_2_2 ... ok +test joins::hash_join::exec::tests::test_collect_left_multiple_partitions_join ... ok +test joins::nested_loop_join::tests::join_inner_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_left_mark_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_left_anti_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_full_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_left_semi_with_filter::batch_size_2_2 ... ok +test joins::nested_loop_join::tests::join_left_mark_with_filter::batch_size_2_2 ... ok +test joins::nested_loop_join::tests::join_left_anti_with_filter::batch_size_2_2 ... ok +test joins::nested_loop_join::tests::join_left_semi_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_left_anti_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_left_mark_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_left_semi_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_left_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_right_anti_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_left_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_right_anti_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_right_mark_with_filter::batch_size_2_2 ... ok +test joins::nested_loop_join::tests::join_right_mark_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_left_with_filter::batch_size_2_2 ... ok +test joins::nested_loop_join::tests::join_right_mark_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_right_semi_with_filter::batch_size_1_1 ... ok +test joins::nested_loop_join::tests::join_right_semi_with_filter::batch_size_3_16 ... ok +test joins::nested_loop_join::tests::join_right_anti_with_filter::batch_size_2_2 ... ok +test joins::nested_loop_join::tests::join_right_semi_with_filter::batch_size_2_2 ... ok +test joins::nested_loop_join::tests::join_right_with_filter::batch_size_1_1 ... ok +test joins::piecewise_merge_join::classic_join::tests::join_date64_right_less_than ... ok +test joins::piecewise_merge_join::classic_join::tests::join_date32_inner_less_than ... ok +test joins::piecewise_merge_join::classic_join::tests::join_date64_inner_less_than ... ok +test joins::piecewise_merge_join::classic_join::tests::join_full_greater_than_equal_to ... ok +test joins::nested_loop_join::tests::test_overallocation ... ok +test joins::nested_loop_join::tests::join_right_with_filter::batch_size_3_16 ... ok +test joins::piecewise_merge_join::classic_join::tests::join_inner_empty_right ... ok +test joins::nested_loop_join::tests::join_right_with_filter::batch_size_2_2 ... ok +test joins::piecewise_merge_join::classic_join::tests::join_inner_empty_left ... ok +test joins::piecewise_merge_join::classic_join::tests::join_inner_greater_than_equal_to ... ok +test joins::piecewise_merge_join::classic_join::tests::join_inner_less_than_equal_with_dups ... ok +test joins::piecewise_merge_join::classic_join::tests::join_inner_less_than ... ok +test joins::piecewise_merge_join::classic_join::tests::join_inner_single_row_left_less_than ... ok +test joins::piecewise_merge_join::classic_join::tests::join_inner_less_than_unsorted ... ok +test joins::piecewise_merge_join::classic_join::tests::join_left_greater_than ... ok +test joins::piecewise_merge_join::classic_join::tests::join_left_less_than_equal_with_left_nulls_on_no_match ... ok +test joins::piecewise_merge_join::classic_join::tests::join_inner_greater_than_unsorted_right ... ok +test joins::piecewise_merge_join::classic_join::tests::join_right_greater_than ... ok +test joins::piecewise_merge_join::classic_join::tests::join_right_greater_than_equal_with_right_nulls_on_no_match ... ok +test joins::sort_merge_join::tests::join_inner_one ... ok +test joins::sort_merge_join::tests::join_date64 ... ok +test joins::piecewise_merge_join::classic_join::tests::join_right_less_than ... ok +test joins::sort_merge_join::tests::join_binary ... ok +test joins::sort_merge_join::tests::join_full_one ... ok +test joins::sort_merge_join::tests::join_date32 ... ok +test joins::sort_merge_join::tests::join_full_multiple_batches ... ok +test joins::sort_merge_join::tests::join_fixed_size_binary ... ok +test joins::sort_merge_join::tests::join_inner_two_two ... ok +test joins::sort_merge_join::tests::join_left_anti ... ok +test joins::sort_merge_join::tests::join_inner_two ... ok +test joins::sort_merge_join::tests::join_inner_output_two_batches ... ok +test joins::sort_merge_join::tests::join_left_mark ... ok +test joins::sort_merge_join::tests::join_inner_with_nulls ... ok +test joins::sort_merge_join::tests::join_left_mark_different_columns_count_with_filter ... ok +test joins::sort_merge_join::tests::join_left_multiple_batches ... ok +test joins::sort_merge_join::tests::join_left_different_columns_count_with_filter ... ok +test joins::sort_merge_join::tests::join_inner_with_nulls_with_options ... ok +test joins::sort_merge_join::tests::join_left_one ... ok +test joins::sort_merge_join::tests::join_right_anti_filtered_with_mismatched_columns ... ok +test joins::sort_merge_join::tests::join_right_anti_two_two ... ok +test joins::sort_merge_join::tests::join_right_anti_output_two_batches ... ok +test joins::sort_merge_join::tests::join_right_anti_with_nulls ... ok +test joins::sort_merge_join::tests::join_left_semi ... ok +test joins::sort_merge_join::tests::join_right_anti_one_one ... ok +test joins::sort_merge_join::tests::join_left_sort_order ... ok +test joins::sort_merge_join::tests::join_right_anti_two_with_filter ... ok +test joins::sort_merge_join::tests::join_right_anti_with_nulls_with_options ... ok +test joins::sort_merge_join::tests::join_right_semi_one ... ok +test joins::sort_merge_join::tests::join_right_semi_with_nulls ... ok +test joins::sort_merge_join::tests::join_right_mark_different_columns_count_with_filter ... ok +test joins::sort_merge_join::tests::join_right_different_columns_count_with_filter ... ok +test joins::sort_merge_join::tests::join_right_mark ... ok +test joins::sort_merge_join::tests::join_right_semi_two ... ok +test joins::sort_merge_join::tests::join_right_semi_with_nulls_with_options ... ok +test joins::sort_merge_join::tests::join_right_semi_output_two_batches ... ok +test joins::sort_merge_join::tests::join_right_sort_order ... ok +test joins::sort_merge_join::tests::join_right_multiple_batches ... ok +test joins::sort_merge_join::tests::join_right_semi_two_with_filter ... ok +test joins::sort_merge_join::tests::join_with_duplicated_column_names ... ok +test joins::sort_merge_join::tests::join_right_one ... ok +test joins::sort_merge_join::tests::test_partition_statistics ... ok +test joins::sort_merge_join::tests::overallocation_single_batch_no_spill ... ok +test joins::stream_join_utils::tests::build_sorted_expr ... ok +test joins::stream_join_utils::tests::find_expr_inside_expr ... ok +test joins::sort_merge_join::tests::overallocation_multi_batch_no_spill ... ok +test joins::stream_join_utils::tests::sorted_filter_expr_build ... ok +test joins::stream_join_utils::tests::test_column_collector ... ok +test joins::sort_merge_join::tests::test_semi_join_filtered_mask ... ok +test joins::stream_join_utils::tests::test_column_exchange ... ok +test joins::sort_merge_join::tests::test_left_outer_join_filtered_mask ... ok +test joins::sort_merge_join::tests::test_anti_join_filtered_mask ... ok +test joins::stream_join_utils::tests::test_shrink_if_necessary ... ok +test joins::sort_merge_join::tests::overallocation_single_batch_spill ... ok +test joins::symmetric_hash_join::tests::build_null_columns_first_descending ... ok +test joins::symmetric_hash_join::tests::build_null_columns_first ... ok +test joins::symmetric_hash_join::tests::build_null_columns_last ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_01_JoinType__Inner::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_01_JoinType__Inner::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_02_JoinType__Left::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_02_JoinType__Left::cardinality_2__12_17_ ... ok +test joins::hash_join::exec::tests::join_split_batch ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_equivalence ... ok +test joins::sort_merge_join::tests::overallocation_multi_batch_spill ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_04_JoinType__RightSemi::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_03_JoinType__Right::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_03_JoinType__Right::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_04_JoinType__RightSemi::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_08_JoinType__RightAnti::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_07_JoinType__LeftMark::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_09_JoinType__RightMark::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_08_JoinType__RightAnti::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_07_JoinType__LeftMark::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_01_JoinType__Inner::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_01_JoinType__Inner::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_09_JoinType__RightMark::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_01_JoinType__Inner::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_01_JoinType__Inner::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_01_JoinType__Inner::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_01_JoinType__Inner::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_02_JoinType__Left::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_10_JoinType__Full::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_02_JoinType__Left::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_02_JoinType__Left::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_02_JoinType__Left::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_02_JoinType__Left::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_03_JoinType__Right::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_02_JoinType__Left::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric::join_type_10_JoinType__Full::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::complex_join_all_one_ascending_numeric_missing_stat ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_03_JoinType__Right::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_03_JoinType__Right::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_04_JoinType__RightSemi::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_03_JoinType__Right::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_04_JoinType__RightSemi::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_03_JoinType__Right::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_04_JoinType__RightSemi::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_03_JoinType__Right::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_04_JoinType__RightSemi::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_05_JoinType__LeftSemi::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_04_JoinType__RightSemi::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_05_JoinType__LeftSemi::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_04_JoinType__RightSemi::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_05_JoinType__LeftSemi::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_05_JoinType__LeftSemi::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_05_JoinType__LeftSemi::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_05_JoinType__LeftSemi::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_06_JoinType__LeftAnti::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_06_JoinType__LeftAnti::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_06_JoinType__LeftAnti::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_06_JoinType__LeftAnti::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_06_JoinType__LeftAnti::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_07_JoinType__LeftMark::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_06_JoinType__LeftAnti::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_07_JoinType__LeftMark::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_07_JoinType__LeftMark::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_07_JoinType__LeftMark::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_07_JoinType__LeftMark::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_07_JoinType__LeftMark::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_08_JoinType__RightAnti::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_08_JoinType__RightAnti::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_08_JoinType__RightAnti::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_08_JoinType__RightAnti::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_08_JoinType__RightAnti::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_08_JoinType__RightAnti::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_09_JoinType__RightMark::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_09_JoinType__RightMark::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_09_JoinType__RightMark::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_09_JoinType__RightMark::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_09_JoinType__RightMark::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_09_JoinType__RightMark::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_10_JoinType__Full::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_01_JoinType__Inner::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_01_JoinType__Inner::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_10_JoinType__Full::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_10_JoinType__Full::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_01_JoinType__Inner::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_10_JoinType__Full::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_10_JoinType__Full::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_ascending_numeric::join_type_10_JoinType__Full::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_01_JoinType__Inner::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_01_JoinType__Inner::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_01_JoinType__Inner::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_02_JoinType__Left::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_02_JoinType__Left::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_02_JoinType__Left::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_03_JoinType__Right::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_02_JoinType__Left::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_02_JoinType__Left::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_02_JoinType__Left::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_03_JoinType__Right::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_03_JoinType__Right::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_03_JoinType__Right::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_03_JoinType__Right::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_04_JoinType__RightSemi::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_04_JoinType__RightSemi::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_04_JoinType__RightSemi::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_04_JoinType__RightSemi::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_04_JoinType__RightSemi::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_04_JoinType__RightSemi::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_03_JoinType__Right::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_05_JoinType__LeftSemi::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_05_JoinType__LeftSemi::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_05_JoinType__LeftSemi::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_05_JoinType__LeftSemi::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_05_JoinType__LeftSemi::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_05_JoinType__LeftSemi::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_06_JoinType__LeftAnti::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_06_JoinType__LeftAnti::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_06_JoinType__LeftAnti::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_06_JoinType__LeftAnti::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_06_JoinType__LeftAnti::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_07_JoinType__LeftMark::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_06_JoinType__LeftAnti::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_07_JoinType__LeftMark::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_07_JoinType__LeftMark::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_07_JoinType__LeftMark::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_07_JoinType__LeftMark::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_08_JoinType__RightAnti::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_08_JoinType__RightAnti::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_08_JoinType__RightAnti::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_07_JoinType__LeftMark::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_08_JoinType__RightAnti::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_08_JoinType__RightAnti::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_09_JoinType__RightMark::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_09_JoinType__RightMark::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_08_JoinType__RightAnti::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_09_JoinType__RightMark::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_09_JoinType__RightMark::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_09_JoinType__RightMark::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_09_JoinType__RightMark::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_10_JoinType__Full::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_10_JoinType__Full::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_10_JoinType__Full::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_04_JoinType__RightSemi ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_01_JoinType__Inner ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_05_JoinType__LeftSemi ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_10_JoinType__Full::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_10_JoinType__Full::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_02_JoinType__Left ... ok +test joins::symmetric_hash_join::tests::join_all_one_descending_numeric_particular::join_type_10_JoinType__Full::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_03_JoinType__Right ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_06_JoinType__LeftAnti ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_08_JoinType__RightAnti ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_07_JoinType__LeftMark ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_01_JoinType__Inner::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_09_JoinType__RightMark ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_01_JoinType__Inner::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_filter::join_type_10_JoinType__Full ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_01_JoinType__Inner::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_01_JoinType__Inner::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_01_JoinType__Inner::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_02_JoinType__Left::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_02_JoinType__Left::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_01_JoinType__Inner::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_02_JoinType__Left::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_02_JoinType__Left::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_03_JoinType__Right::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_02_JoinType__Left::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_03_JoinType__Right::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_02_JoinType__Left::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_03_JoinType__Right::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_04_JoinType__RightSemi::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_03_JoinType__Right::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_04_JoinType__RightSemi::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_03_JoinType__Right::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_04_JoinType__RightSemi::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_04_JoinType__RightSemi::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_04_JoinType__RightSemi::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_04_JoinType__RightSemi::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_05_JoinType__LeftSemi::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_03_JoinType__Right::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_05_JoinType__LeftSemi::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_05_JoinType__LeftSemi::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_05_JoinType__LeftSemi::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_05_JoinType__LeftSemi::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_06_JoinType__LeftAnti::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_05_JoinType__LeftSemi::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_06_JoinType__LeftAnti::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_06_JoinType__LeftAnti::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_06_JoinType__LeftAnti::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_06_JoinType__LeftAnti::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_06_JoinType__LeftAnti::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_08_JoinType__RightAnti::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_07_JoinType__LeftMark::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_07_JoinType__LeftMark::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_07_JoinType__LeftMark::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_07_JoinType__LeftMark::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_07_JoinType__LeftMark::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_08_JoinType__RightAnti::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_07_JoinType__LeftMark::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_08_JoinType__RightAnti::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_08_JoinType__RightAnti::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_08_JoinType__RightAnti::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_08_JoinType__RightAnti::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_09_JoinType__RightMark::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_09_JoinType__RightMark::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_09_JoinType__RightMark::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_09_JoinType__RightMark::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_09_JoinType__RightMark::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_09_JoinType__RightMark::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_10_JoinType__Full::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_10_JoinType__Full::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_10_JoinType__Full::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_10_JoinType__Full::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_10_JoinType__Full::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_01_JoinType__Inner::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_01_JoinType__Inner::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_02_JoinType__Left::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_02_JoinType__Left::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_03_JoinType__Right::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::join_without_sort_information::join_type_10_JoinType__Full::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_04_JoinType__RightSemi::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_04_JoinType__RightSemi::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_03_JoinType__Right::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_08_JoinType__RightAnti::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_07_JoinType__LeftMark::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_07_JoinType__LeftMark::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_08_JoinType__RightAnti::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_09_JoinType__RightMark::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_09_JoinType__RightMark::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_10_JoinType__Full::cardinality_1__4_5_ ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::test_with_interval_columns::join_type_10_JoinType__Full::cardinality_2__12_17_ ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_4_3 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_5_4 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_6_5 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_ascending_float_pruning::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_01_JoinType__Inner::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_3_2 ... ok +test aggregates::group_values::multi_group_by::bytes::tests::test_byte_group_value_builder_overflow ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_02_JoinType__Left::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_02_JoinType__Left::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_04_JoinType__RightSemi::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_03_JoinType__Right::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_05_JoinType__LeftSemi::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_04_JoinType__RightSemi::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_05_JoinType__LeftSemi::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_06_JoinType__LeftAnti::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_03_JoinType__Right::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_06_JoinType__LeftAnti::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_07_JoinType__LeftMark::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_07_JoinType__LeftMark::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_08_JoinType__RightAnti::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_2_1 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_08_JoinType__RightAnti::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::utils::tests::check_collision ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_09_JoinType__RightMark::cardinality_1__4_5_::case_expr_1_0 ... ok +test joins::utils::tests::check_error_nesting ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_2_1 ... ok +test joins::utils::tests::check_in_right ... ok +test joins::utils::tests::check_valid ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_1_0 ... ok +test joins::utils::tests::check_not_in_left ... ok +test joins::utils::tests::check_not_in_right ... ok +test joins::utils::tests::test_batch_splitter::batch_size_1_1::num_rows_1_1 ... ok +test joins::utils::tests::test_batch_splitter::batch_size_1_1::num_rows_3_50 ... ok +test joins::utils::tests::test_anti_semi_join_cardinality ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_09_JoinType__RightMark::cardinality_2__12_17_::case_expr_3_2 ... ok +test joins::utils::tests::test_batch_splitter::batch_size_1_1::num_rows_2_6 ... ok +test joins::utils::tests::test_batch_splitter::batch_size_2_3::num_rows_1_1 ... ok +test joins::utils::tests::test_batch_splitter::batch_size_2_3::num_rows_2_6 ... ok +test joins::utils::tests::test_batch_splitter::batch_size_3_11::num_rows_1_1 ... ok +test joins::utils::tests::test_batch_splitter::batch_size_2_3::num_rows_3_50 ... ok +test joins::utils::tests::test_batch_splitter::batch_size_3_11::num_rows_2_6 ... ok +test joins::utils::tests::test_batch_splitter::batch_size_3_11::num_rows_3_50 ... ok +test joins::utils::tests::test_inner_join_cardinality_multiple_column ... ok +test joins::utils::tests::test_calculate_join_output_ordering ... ok +test joins::utils::tests::test_inner_join_cardinality_decimal_range ... ok +test joins::utils::tests::test_join_cardinality_when_one_column_is_disjoint ... ok +test joins::utils::tests::test_join_cardinality ... ok +test joins::utils::tests::test_join_metadata ... ok +test joins::utils::tests::test_inner_join_cardinality_single_column ... ok +test joins::utils::tests::test_join_schema ... ok +test limit::tests::limit_equals_batch_size ... ok +test joins::utils::tests::test_semi_join_cardinality_absent_rows ... ok +test joins::utils::tests::test_swap_reverting_projection ... ok +test limit::tests::limit_early_shutdown ... ok +test limit::tests::skip_3_fetch_10_stats ... ok +test limit::tests::limit ... ok +test limit::tests::limit_no_column ... ok +test limit::tests::skip_3_fetch_none ... ok +test limit::tests::skip_400_fetch_none ... ok +test limit::tests::skip_400_fetch_1 ... ok +test limit::tests::test_row_number_statistics_for_local_limit ... ok +test limit::tests::skip_none_fetch_50 ... ok +test limit::tests::skip_none_fetch_none ... ok +test limit::tests::skip_401_fetch_none ... ok +test memory::lazy_memory_tests::test_lazy_memory_exec ... ok +test memory::lazy_memory_tests::test_lazy_memory_exec_invalid_partition ... ok +test memory::lazy_memory_tests::test_lazy_memory_exec_reset_state ... ok +test placeholder_row::tests::produce_one_row ... ok +test memory::lazy_memory_tests::test_generate_series_metrics_integration ... ok +test placeholder_row::tests::invalid_execute ... ok +test placeholder_row::tests::produce_one_row_multiple_partition ... ok +test placeholder_row::tests::with_new_children ... ok +test projection::tests::project_no_column ... ok +test projection::tests::project_old_syntax ... ok +test projection::tests::test_collect_column_indices ... ok +test projection::tests::test_basic_dyn_filter_projection_pushdown_update_child ... ok +test projection::tests::test_filter_pushdown_with_alias ... ok +test limit::tests::test_row_number_statistics_for_global_limit ... ok +test projection::tests::test_filter_pushdown_with_mixed_columns ... ok +test projection::tests::test_filter_pushdown_with_multiple_aliases ... ok +test projection::tests::test_filter_pushdown_with_unknown_column ... ok +test projection::tests::test_filter_pushdown_with_complex_expression ... ok +test projection::tests::test_filter_pushdown_with_swapped_aliases ... ok +test projection::tests::test_join_table_borders ... ok +test projection::tests::test_projection_statistics_uses_input_schema ... ok +test repartition::distributor_channels::tests::test_close_channel_by_dropping_rx_clears_data ... ok +test repartition::distributor_channels::tests::test_close_channel_by_dropping_rx_on_closed_gate ... ok +test repartition::distributor_channels::tests::test_close_channel_by_dropping_rx_on_open_gate ... ok +test repartition::distributor_channels::tests::test_drop_rx_three_channels ... ok +test repartition::distributor_channels::tests::test_gate ... ok +test repartition::distributor_channels::tests::test_meta_poll_pending_waker ... ok +test repartition::distributor_channels::tests::test_close_channel_by_dropping_tx ... ok +test repartition::distributor_channels::tests::test_multi_sender ... ok +test repartition::distributor_channels::tests::test_meta_poll_pending_wrong_state - should panic ... ok +test repartition::distributor_channels::tests::test_meta_poll_ready_wrong_state - should panic ... ok +test repartition::distributor_channels::tests::test_panic_poll_recv_future_after_ready_none - should panic ... ok +test repartition::distributor_channels::tests::test_panic_poll_recv_future_after_ready_some - should panic ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_01_JoinType__Inner::cardinality_1__4_5_::case_expr_1_0 ... ok +test repartition::distributor_channels::tests::test_panic_poll_send_future_after_ready_err - should panic ... ok +test repartition::distributor_channels::tests::test_poll_empty_channel_twice ... ok +test repartition::distributor_channels::tests::test_panic_poll_send_future_after_ready_ok - should panic ... ok +test repartition::distributor_channels::tests::test_single_channel_no_gate ... ok +test repartition::test::test_preserve_order_input_not_sorted ... ok +test repartition::test::test_preserve_order_one_partition ... ok +test repartition::test::test_repartition ... ok +test repartition::test::test_preserve_order ... ok +test repartition::tests::error_for_input_exec ... ok +test repartition::tests::hash_repartition_with_dropping_output_stream ... ok +test repartition::tests::hash_repartition_avoid_empty_batch ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_2_1 ... ok +test repartition::tests::many_to_many_round_robin ... ok +test repartition::tests::many_to_one_round_robin ... ok +test repartition::tests::many_to_many_hash_partition ... ok +test repartition::test::test_hash_partitioning_with_spilling ... ok +test repartition::tests::oom ... ok +test repartition::tests::one_to_many_round_robin ... ok +test repartition::tests::repartition_with_error_in_stream ... ok +test repartition::tests::many_to_many_round_robin_within_tokio_task ... ok +test repartition::tests::robin_repartition_with_dropping_output_stream ... ok +test repartition::tests::repartition_with_delayed_stream ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_2_1 ... ok +test repartition::test::test_preserve_order_with_spilling ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_3_2 ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_1_0 ... ok +test repartition::tests::unsupported_partitioning ... ok +test repartition::tests::repartition_without_spilling ... ok +test sorts::cursor::tests::test_primitive_nulls_first ... ok +test sorts::partial_sort::tests::test_drop_cancel ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_10_JoinType__Full::cardinality_2__12_17_::case_expr_3_2 ... ok +test repartition::tests::test_repartition_with_coalescing ... ok +test sorts::partial_sort::tests::test_lex_sort_by_float ... ok +test sorts::partial_sort::tests::test_partial_sort ... ok +test sorts::partial_sort::tests::test_partial_sort_no_empty_batches ... ok +test sorts::partial_sort::tests::test_partial_sort2 ... ok +test sorts::partial_sort::tests::test_sort_metadata ... ok +test sorts::partial_sort::tests::test_partial_sort_with_homogeneous_batches ... ok +test sorts::partial_sort::tests::test_partial_sort_with_fetch ... ok +test sorts::sort::tests::should_return_stream_with_batches_in_the_requested_size_when_having_a_single_batch ... ok +test sorts::partial_sort::tests::test_partitioned_input_partial_sort ... ok +test sorts::sort::tests::test_batch_reservation_error ... ok +test sorts::sort::tests::test_drop_cancel ... ok +test sorts::sort::tests::test_empty_sort_batch ... ok +test sorts::sort::tests::test_get_reserved_bytes_for_record_batch_with_sliced_batches ... ok +test sorts::sort::tests::test_in_mem_sort ... ok +test sorts::sort::tests::test_lex_sort_by_mixed_types ... ok +test sorts::sort::tests::test_lex_sort_by_float ... ok +test sorts::sort::tests::test_sort_batch_chunked_basic ... ok +test sorts::sort::tests::test_sort_batch_chunked_empty_batch ... ok +test sorts::sort::tests::test_sort_batch_chunked_smaller_than_batch_size ... ok +test sorts::sort::tests::test_sort_batch_chunked_exact_multiple ... ok +test sorts::partial_sort::tests::test_partitioned_input_partial_sort_with_fetch ... ok +test sorts::sort::tests::test_sort_metadata ... ok +test sorts::sort::tests::test_sort_memory_reduction_per_batch ... ok +test sorts::sort::tests::should_return_stream_with_batches_in_the_requested_size_when_sorting_in_place ... ok +test sorts::sort::tests::should_return_stream_with_batches_in_the_requested_size ... ok +test sorts::sort::tests::topk_unbounded_source ... ok +test sorts::sort_preserving_merge::tests::test_drop_cancel ... ok +test sorts::sort_preserving_merge::tests::test_merge_interleave ... ok +test sorts::sort_preserving_merge::tests::test_merge_metrics ... ok +test repartition::tests::test_repartition_ordering_with_spilling ... ok +test sorts::sort_preserving_merge::tests::test_merge_no_overlap ... ok +test sorts::sort_preserving_merge::tests::test_merge_some_overlap ... ok +test sorts::sort_preserving_merge::tests::test_nulls ... ok +test sorts::sort_preserving_merge::tests::test_merge_three_partitions ... ok +test repartition::tests::repartition_with_partial_spilling ... ok +test repartition::tests::repartition_with_spilling ... ok +test sorts::sort::tests::test_sort_fetch_memory_calculation ... ok +test sorts::sort_preserving_merge::tests::test_sort_merge_single_partition_with_fetch ... ok +test sorts::sort_preserving_merge::tests::test_sort_merge_single_partition_without_fetch ... ok +test sorts::sort_preserving_merge::tests::test_partition_sort ... ok +test sorts::sort_preserving_merge::tests::test_spm_congestion ... ok +test spill::spill_manager::tests::check_sliced_size_for_string_view_array ... ok +test repartition::tests::test_drop_cancel ... ok +test sorts::sort_preserving_merge::tests::test_stable_sort ... ok +test spill::spill_pool::tests::test_basic_write_and_read ... ok +test spill::spill_pool::tests::test_disk_usage_decreases_as_files_consumed ... ok +test spill::spill_pool::tests::test_empty_batch_skipping ... ok +test sorts::sort::tests::test_sort_spill ... ok +test spill::spill_pool::tests::test_exact_size_boundary ... ok +test spill::spill_pool::tests::test_multiple_batches_sequential ... ok +test sorts::sort_preserving_merge::tests::test_partition_sort_streaming_input ... ok +test sorts::sort_preserving_merge::tests::test_partition_sort_streaming_input_output ... ok +test spill::spill_pool::tests::test_reader_catches_up_to_writer ... ok +test spill::spill_pool::tests::test_multiple_rotations ... ok +test joins::symmetric_hash_join::tests::testing_with_temporal_columns::join_type_10_JoinType__Full::cardinality_1__4_5_::case_expr_1_0 ... ok +test spill::spill_pool::tests::test_rotation_triggered_by_size ... ok +test spill::spill_pool::tests::test_single_batch_larger_than_limit ... ok +test spill::tests::test_alignment_for_schema ... ok +test spill::spill_pool::tests::test_single_batch_write_read ... ok +test spill::spill_pool::tests::test_very_small_max_file_size ... ok +test spill::spill_pool::tests::test_writer_drop_finalizes_file ... ok +test spill::tests::test_batch_spill_and_read ... ok +test spill::spill_pool::tests::test_reader_starts_after_writer_finishes ... ok +test spill::tests::test_batch_spill_by_size ... ok +test spill::tests::test_in_progress_spill_file_append_and_finish ... ok +test spill::tests::test_batch_spill_and_read_dictionary_arrays ... ok +test spill::tests::test_in_progress_spill_file_write_no_batches ... ok +test sorts::sort::tests::should_return_stream_with_batches_in_the_requested_size_when_having_to_spill ... ok +test stream::test::batch_split_stream_basic_functionality ... ok +test spill::tests::test_spill_manager_spill_record_batch_and_finish ... ok +test spill::tests::test_real_time_spill_metrics ... ok +test stream::test::record_batch_receiver_stream_error_does_not_drive_completion ... ok +test stream::test::record_batch_receiver_stream_builder_spawn_on_runtime ... ok +test stream::test::test_reservation_stream_error_handling ... ok +test stream::test::record_batch_receiver_stream_propagates_panics_early_shutdown - should panic ... ok +test stream::test::record_batch_receiver_stream_propagates_panics - should panic ... ok +test stream::test::test_reservation_stream_shrinks_on_poll ... ok +test spill::tests::test_reading_more_spills_than_tokio_blocking_threads ... ok +test streaming::test::test_limit ... ok +test topk::tests::test_record_batch_store_size ... ok +test streaming::test::test_no_limit ... ok +test union::tests::test_union_empty_inputs ... ok +test union::tests::test_stats_union ... ok +test topk::tests::test_topk_marks_filter_complete ... ok +test union::tests::test_union_schema_empty_inputs ... ok +test union::tests::test_union_schema_mismatch ... ok +test topk::tests::test_try_finish_marks_finished_with_prefix ... ok +test union::tests::test_union_schema_multiple_inputs ... ok +test union::tests::test_union_single_input ... ok +test union::tests::test_union_partitions ... ok +test unnest::tests::test_create_take_indices ... ok +test union::tests::test_union_equivalence_properties ... ok +test unnest::tests::test_unnest_list_array ... ok +test unnest::tests::test_longest_list_length ... ok +test spill::tests::test_spill_compression ... ok +test unnest::tests::test_build_batch_list_arr_recursive ... ok +test windows::tests::test_calc_requirements ... ok +test windows::tests::test_drop_cancel ... ok +test windows::tests::test_satisfy_non_nullable ... ok +test windows::bounded_window_agg_exec::tests::test_window_nth_value_bounded_memoize ... ok +test work_table::tests::test_work_table ... ok +test windows::tests::test_satisfy_nullable ... ok +test work_table::tests::test_work_table_exec ... ok +test windows::tests::test_get_window_mode ... ok +test windows::tests::test_get_window_mode_exhaustive ... ok +test stream::test::record_batch_receiver_stream_drop_cancel ... ok +test spill::spill_pool::tests::test_concurrent_reader_writer ... ok +test sorts::sort::tests::test_sort_spill_utf8_strings ... ok +test spill::spill_pool::tests::test_empty_writer ... ok +test sorts::sort_preserving_merge::tests::test_round_robin_tie_breaker_fail ... ok +test sorts::sort_preserving_merge::tests::test_async ... ok +test windows::bounded_window_agg_exec::tests::bounded_window_exec_linear_mode_range_information ... ok +test sorts::sort_preserving_merge::tests::test_round_robin_tie_breaker_success ... ok + +test result: ok. 1246 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.99s + + Running unittests src/lib.rs (target/debug/deps/datafusion_proto-5561137ba7f73c5c) + +running 2 tests +test physical_plan::from_proto::tests::partitioned_file_from_proto_invalid_path ... ok +test physical_plan::from_proto::tests::partitioned_file_path_roundtrip_percent_encoded ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/proto_integration.rs (target/debug/deps/proto_integration-834c1dd8a8ef58b5) + +running 135 tests +test cases::roundtrip_logical_plan::round_trip_scalar_types ... ok +test cases::roundtrip_logical_plan::round_trip_datatype ... ok +test cases::roundtrip_logical_plan::round_trip_scalar_values_and_data_types ... ok +test cases::roundtrip_logical_plan::roundtrip_case_with_null ... ok +test cases::roundtrip_logical_plan::roundtrip_between ... ok +test cases::roundtrip_logical_plan::roundtrip_cube ... ok +test cases::roundtrip_logical_plan::roundtrip_case ... ok +test cases::roundtrip_logical_plan::roundtrip_count_distinct ... ok +test cases::roundtrip_logical_plan::roundtrip_count ... ok +test cases::roundtrip_logical_plan::roundtrip_cast ... ok +test cases::roundtrip_logical_plan::roundtrip_aggregate_udf_extension_codec ... ok +test cases::roundtrip_logical_plan::roundtrip_aggregate_udf ... ok +test cases::roundtrip_logical_plan::roundtrip_field ... ok +test cases::roundtrip_logical_plan::roundtrip_inlist ... ok +test cases::roundtrip_logical_plan::roundtrip_grouping_sets ... ok +test cases::roundtrip_logical_plan::roundtrip_dfschema ... ok +test cases::roundtrip_logical_plan::roundtrip_ilike ... ok +test cases::roundtrip_logical_plan::roundtrip_is_null ... ok +test cases::roundtrip_logical_plan::roundtrip_is_not_null ... ok +test cases::roundtrip_logical_plan::roundtrip_like ... ok +test cases::roundtrip_logical_plan::roundtrip_binary_op ... ok +test cases::roundtrip_logical_plan::roundtrip_custom_listing_tables ... ok +test cases::roundtrip_logical_plan::roundtrip_custom_listing_tables_schema_table_scan_projection ... ok +test cases::roundtrip_logical_plan::roundtrip_custom_listing_tables_schema ... ok +test cases::roundtrip_logical_plan::roundtrip_custom_tables ... ok +test cases::roundtrip_logical_plan::roundtrip_arrow_scan ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_copy_to_json ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_aggregation_with_pk ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_aggregation ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_copy_to_parquet ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_prepared_statement_with_metadata ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_distinct_on ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_sort ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_unnest ... ok +test cases::roundtrip_logical_plan::roundtrip_negative ... ok +test cases::roundtrip_logical_plan::roundtrip_not ... ok +test cases::roundtrip_logical_plan::roundtrip_null_literal ... ok +test cases::roundtrip_logical_plan::roundtrip_null_scalar_values ... ok +test cases::roundtrip_logical_plan::roundtrip_qualified_wildcard ... ok +test cases::roundtrip_logical_plan::roundtrip_custom_memory_tables ... ok +test cases::roundtrip_logical_plan::roundtrip_rollup ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_copy_to_arrow ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_copy_to_sql_options ... ok +test cases::roundtrip_logical_plan::roundtrip_schema ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_copy_to_writer_options ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_dml ... ok +test cases::roundtrip_logical_plan::roundtrip_scalar_udf_extension_codec ... ok +test cases::roundtrip_logical_plan::roundtrip_scalar_udf ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_with_extension ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_copy_to_csv ... ok +test cases::roundtrip_logical_plan::roundtrip_wildcard ... ok +test cases::roundtrip_logical_plan::roundtrip_unnest ... ok +test cases::roundtrip_logical_plan::roundtrip_substr ... ok +test cases::roundtrip_logical_plan::roundtrip_similar_to ... ok +test cases::roundtrip_logical_plan::roundtrip_logical_plan_with_view_scan ... ok +test cases::roundtrip_logical_plan::roundtrip_try_cast ... ok +test cases::roundtrip_logical_plan::roundtrip_window ... ok +test cases::roundtrip_logical_plan::roundtrip_mixed_case_table_reference ... ok +test cases::roundtrip_physical_plan::custom_proto_converter_intercepts ... ok +test cases::roundtrip_physical_plan::roundtrip_aggregate_udaf ... ok +test cases::roundtrip_physical_plan::analyze_roundtrip_unoptimized ... ok +test cases::roundtrip_physical_plan::roundtrip_aggregate_with_approx_pencentile_cont ... ok +test cases::roundtrip_physical_plan::roundtrip_aggregate_with_limit ... ok +test cases::roundtrip_logical_plan::roundtrip_single_count_distinct ... ok +test cases::roundtrip_physical_plan::roundtrip_aggregate_udf_extension_codec ... ok +test cases::roundtrip_physical_plan::roundtrip_aggregate_with_sort ... ok +test cases::roundtrip_physical_plan::roundtrip_coalesce_partitions_with_fetch ... ok +test cases::roundtrip_physical_plan::roundtrip_aggregate ... ok +test cases::roundtrip_physical_plan::roundtrip_analyze ... ok +test cases::roundtrip_physical_plan::roundtrip_coalesce_batches_with_fetch ... ok +test cases::roundtrip_physical_plan::roundtrip_csv_sink ... ok +test cases::roundtrip_physical_plan::roundtrip_empty ... ok +test cases::roundtrip_physical_plan::roundtrip_async_func_exec ... ok +test cases::roundtrip_physical_plan::roundtrip_global_skip_no_limit ... ok +test cases::roundtrip_physical_plan::roundtrip_filter_with_not_and_in_list ... ok +test cases::roundtrip_physical_plan::roundtrip_date_time_interval ... ok +test cases::roundtrip_physical_plan::roundtrip_coalesce ... ok +test cases::roundtrip_physical_plan::roundtrip_global_limit ... ok +test cases::roundtrip_physical_plan::roundtrip_generate_series ... ok +test cases::roundtrip_physical_plan::roundtrip_hash_table_lookup_expr_to_lit ... ok +test cases::roundtrip_physical_plan::roundtrip_json_sink ... ok +test cases::roundtrip_physical_plan::roundtrip_hash_expr ... ok +test cases::roundtrip_physical_plan::roundtrip_interleave ... ok +test cases::roundtrip_physical_plan::roundtrip_like ... ok +test cases::roundtrip_physical_plan::roundtrip_local_limit ... ok +test cases::roundtrip_physical_plan::roundtrip_memory_source ... ok +test cases::roundtrip_physical_plan::roundtrip_parquet_exec_with_custom_predicate_expr ... ok +test cases::roundtrip_physical_plan::roundtrip_empty_projection ... ok +test cases::roundtrip_physical_plan::roundtrip_parquet_exec_with_table_partition_cols ... ok +test cases::roundtrip_physical_plan::roundtrip_parquet_exec_with_pruning_predicate ... ok +test cases::roundtrip_physical_plan::roundtrip_json_source ... ok +test cases::roundtrip_physical_plan::roundtrip_listing_table_with_schema_metadata ... ok +test cases::roundtrip_physical_plan::roundtrip_parquet_sink ... ok +test cases::roundtrip_logical_plan::roundtrip_recursive_query ... ok +test cases::roundtrip_physical_plan::roundtrip_nested_loop_join ... ok +test cases::roundtrip_physical_plan::roundtrip_projection_source ... ok +test cases::roundtrip_physical_plan::roundtrip_hash_join ... ok +test cases::roundtrip_physical_plan::roundtrip_sort ... ok +test cases::roundtrip_physical_plan::roundtrip_scalar_udf_extension_codec ... ok +test cases::roundtrip_physical_plan::roundtrip_scalar_udf ... ok +test cases::roundtrip_physical_plan::roundtrip_sort_preserve_partitioning ... ok +test cases::roundtrip_physical_plan::roundtrip_parquet_select_projection_predicate ... ok +test cases::roundtrip_logical_plan::roundtrip_union_query ... ok +test cases::roundtrip_physical_plan::roundtrip_parquet_select_star ... ok +test cases::roundtrip_physical_plan::roundtrip_unnest ... ok +test cases::roundtrip_physical_plan::roundtrip_parquet_select_projection ... ok +test cases::roundtrip_physical_plan::roundtrip_udwf ... ok +test cases::roundtrip_physical_plan::roundtrip_udwf_extension_codec ... ok +test cases::roundtrip_physical_plan::roundtrip_union ... ok +test cases::roundtrip_physical_plan::roundtrip_window_distinct ... ok +test cases::roundtrip_physical_plan::test_distinct_window_serialization_end_to_end ... ok +test cases::roundtrip_physical_plan::roundtrip_window ... ok +test cases::roundtrip_physical_plan::roundtrip_physical_plan_node ... ok +test cases::roundtrip_physical_plan::roundtrip_parquet_select_star_predicate ... ok +test cases::serialize::exact_roundtrip_linearized_binary_expr ... ok +test cases::roundtrip_physical_plan::roundtrip_sort_merge_join ... ok +test cases::roundtrip_physical_plan::roundtrip_logical_plan_sort_merge_join ... ok +test cases::serialize::roundtrip_deeply_nested_binary_expr_reverse_order ... ok +test cases::serialize::roundtrip_placeholder_with_metadata ... ok +test cases::serialize::roundtrip_qualified_alias ... ok +test cases::serialize::test_expression_serialization_roundtrip ... ok +test cases::roundtrip_physical_plan::test_tpch_part_in_list_query_with_real_parquet_data ... ok +test cases::serialize::udf_roundtrip_with_registry ... ok +test cases::roundtrip_physical_plan::roundtrip_sym_hash_join ... ok +test cases::roundtrip_logical_plan::roundtrip_expr_api ... ok +test cases::roundtrip_physical_plan::test_round_trip_date_part_display ... ok +test cases::serialize::udf_roundtrip_without_registry - should panic ... ok +test cases::roundtrip_physical_plan::test_round_trip_groups_display ... ok +test cases::serialize::bad_decode - should panic ... ok +test cases::roundtrip_physical_plan::test_round_trip_human_display ... ok +test cases::serialize::roundtrip_deeply_nested ... ok +test cases::serialize::roundtrip_deeply_nested_binary_expr ... ok +test cases::roundtrip_physical_plan::test_serialize_deserialize_tpch_queries ... ok +test cases::roundtrip_physical_plan::test_round_trip_tpch_queries ... ok + +test result: ok. 135 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.46s + + Running unittests src/lib.rs (target/debug/deps/datafusion_proto_common-d8888ea251f037dc) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_pruning-0436a0717578620d) + +running 82 tests +test pruning_predicate::tests::prune_bool_const_expr ... ok +test pruning_predicate::tests::prune_int32_col_eq_zero_cast_as_str ... ok +test pruning_predicate::tests::prune_bool_not_column ... ok +test pruning_predicate::tests::prune_bool_column ... ok +test pruning_predicate::tests::prune_int32_col_eq_zero ... ok +test pruning_predicate::tests::prune_bool_not_column_eq_true ... ok +test pruning_predicate::tests::prune_bool_column_eq_true ... ok +test pruning_predicate::tests::prune_api ... ok +test pruning_predicate::tests::prune_int32_col_lt_neg_one ... ok +test pruning_predicate::tests::prune_int32_col_lte_zero_cast ... ok +test pruning_predicate::tests::prune_int32_col_gt_zero ... ok +test pruning_predicate::tests::prune_int32_col_eq_zero_cast ... ok +test pruning_predicate::tests::prune_int32_column_is_known_all_null ... ok +test pruning_predicate::tests::prune_int32_is_null ... ok +test pruning_predicate::tests::prune_all_rows_null_counts ... ok +test pruning_predicate::tests::prune_int32_col_lte_zero ... ok +test pruning_predicate::tests::prune_null_stats ... ok +test pruning_predicate::tests::prune_decimal_data ... ok +test pruning_predicate::tests::prune_missing_statistics ... ok +test pruning_predicate::tests::prune_cast_column_scalar ... ok +test pruning_predicate::tests::prune_utf8_not_like_one ... ok +test pruning_predicate::tests::row_group_predicate_and ... ok +test pruning_predicate::tests::prune_not_eq_data ... ok +test pruning_predicate::tests::prune_utf8_not_eq ... ok +test pruning_predicate::tests::prune_utf8_eq ... ok +test pruning_predicate::tests::prune_utf8_like_one ... ok +test pruning_predicate::tests::row_group_predicate_between ... ok +test pruning_predicate::tests::row_group_predicate_bool ... ok +test pruning_predicate::tests::row_group_predicate_cast_int_string ... ok +test pruning_predicate::tests::prune_utf8_like_many ... ok +test pruning_predicate::tests::row_group_predicate_between_with_in_list ... ok +test pruning_predicate::tests::row_group_predicate_cast_int_int ... ok +test pruning_predicate::tests::row_group_predicate_cast_string_int ... ok +test pruning_predicate::tests::row_group_predicate_cast_string_string ... ok +test pruning_predicate::tests::row_group_predicate_date_dict_string ... ok +test pruning_predicate::tests::row_group_predicate_cast_list ... ok +test pruning_predicate::tests::row_group_predicate_date_date ... ok +test pruning_predicate::tests::prune_with_range_and_contained ... ok +test pruning_predicate::tests::row_group_predicate_date_string ... ok +test pruning_predicate::tests::row_group_predicate_dict_dict_different_value_type ... ok +test pruning_predicate::tests::row_group_predicate_dict_date_dict_date ... ok +test pruning_predicate::tests::row_group_predicate_dict_dict_same_value_type ... ok +test pruning_predicate::tests::row_group_predicate_dict_string_date ... ok +test pruning_predicate::tests::row_group_predicate_eq ... ok +test pruning_predicate::tests::row_group_predicate_gt ... ok +test pruning_predicate::tests::row_group_predicate_complex_literals ... ok +test pruning_predicate::tests::row_group_predicate_dynamic_filter_with_literals ... ok +test pruning_predicate::tests::row_group_predicate_in_list ... ok +test pruning_predicate::tests::row_group_predicate_gt_eq ... ok +test pruning_predicate::tests::row_group_predicate_in_list_empty ... ok +test pruning_predicate::tests::row_group_predicate_in_list_negated ... ok +test pruning_predicate::tests::row_group_predicate_literal_false ... ok +test pruning_predicate::tests::row_group_predicate_in_list_to_many_values ... ok +test pruning_predicate::tests::row_group_predicate_lt ... ok +test pruning_predicate::tests::row_group_predicate_literal_true ... ok +test pruning_predicate::tests::row_group_predicate_literal_null ... ok +test pruning_predicate::tests::row_group_predicate_lt_bool ... ok +test pruning_predicate::tests::row_group_predicate_lt_eq ... ok +test pruning_predicate::tests::row_group_predicate_nested_dict ... ok +test pruning_predicate::tests::row_group_predicate_not ... ok +test pruning_predicate::tests::row_group_predicate_not_bool ... ok +test pruning_predicate::tests::row_group_predicate_not_eq ... ok +test pruning_predicate::tests::row_group_predicate_or ... ok +test pruning_predicate::tests::row_group_predicate_non_boolean ... ok +test pruning_predicate::tests::prune_utf8_not_like_many ... ok +test pruning_predicate::tests::test_build_predicate_expression_with_false ... ok +test pruning_predicate::tests::test_build_predicate_expression_with_and_false ... ok +test pruning_predicate::tests::row_group_predicate_string_date ... ok +test pruning_predicate::tests::test_build_predicate_expression_with_or_false ... ok +test pruning_predicate::tests::test_build_statistics_inconsistent_length ... ok +test pruning_predicate::tests::row_group_predicate_required_columns ... ok +test pruning_predicate::tests::test_build_statistics_no_required_stats ... ok +test pruning_predicate::tests::test_increment_utf8 ... ok +test pruning_predicate::tests::test_rewrite_expr_to_prunable ... ok +test pruning_predicate::tests::test_rewrite_expr_to_prunable_error ... ok +test pruning_predicate::tests::prune_with_contained_two_columns ... ok +test pruning_predicate::tests::test_unique_row_count_field_and_column ... ok +test pruning_predicate::tests::test_rewrite_expr_to_prunable_custom_unhandled_hook ... ok +test pruning_predicate::tests::prune_with_contained_one_column ... ok +test pruning_predicate::tests::test_build_statistics_inconsistent_types ... ok +test pruning_predicate::tests::test_build_statistics_casting ... ok +test pruning_predicate::tests::test_build_statistics_record_batch ... ok + +test result: ok. 82 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s + + Running unittests src/lib.rs (target/debug/deps/datafusion_session-7533477bb298a08e) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_spark-e7f810e8350d02b6) + +running 163 tests +test function::aggregate::try_sum::tests::try_sum_int_negative_overflow_sets_failed ... ok +test function::aggregate::try_sum::tests::try_sum_decimal_overflow_sets_failed ... ok +test function::aggregate::try_sum::tests::try_sum_decimal_basic ... ok +test function::aggregate::try_sum::tests::decimal_10_2_sum_and_schema_widened ... ok +test function::aggregate::try_sum::tests::decimal_5_0_fits_after_widening ... ok +test function::aggregate::try_sum::tests::try_sum_decimal_with_nulls ... ok +test function::aggregate::try_sum::tests::decimal_38_0_max_precision_overflows_to_null ... ok +test function::aggregate::try_sum::tests::try_sum_int_basic ... ok +test function::aggregate::try_sum::tests::float_overflow_behaves_like_spark_sum_infinite ... ok +test function::aggregate::try_sum::tests::try_sum_float_basic ... ok +test function::aggregate::try_sum::tests::try_sum_float_negative_zero_normalizes_to_positive_zero ... ok +test function::aggregate::try_sum::tests::try_sum_int_overflow_sets_failed ... ok +test function::aggregate::try_sum::tests::try_sum_int_with_nulls ... ok +test function::aggregate::try_sum::tests::try_sum_return_type_matches_input ... ok +test function::aggregate::try_sum::tests::try_sum_state_and_evaluate_consistency ... ok +test function::aggregate::try_sum::tests::try_sum_merge_propagates_failure ... ok +test function::aggregate::try_sum::tests::try_sum_state_two_fields_and_merge_ok ... ok +test function::aggregate::try_sum::tests::try_sum_merge_empty_partition_is_not_failure ... ok +test function::aggregate::try_sum::tests::try_sum_decimal_merge_ok_and_failure_propagation ... ok +test function::array::shuffle::tests::test_shuffle_nullability ... ok +test function::bitmap::bitmap_count::tests::test_bitmap_count_nullability ... ok +test function::bitwise::bit_count::tests::test_bit_count_basic ... ok +test function::bitwise::bit_count::tests::test_bit_count_int32 ... ok +test function::bitwise::bit_count::tests::test_bit_count_nullability ... ok +test function::bitwise::bit_count::tests::test_bit_count_int64 ... ok +test function::bitwise::bit_count::tests::test_bit_count_int16 ... ok +test function::bitwise::bit_count::tests::test_bit_count_int8 ... ok +test function::bitwise::bit_count::tests::test_bit_count_nulls ... ok +test function::bitwise::bit_count::tests::test_bit_count_uint16 ... ok +test function::bitwise::bit_count::tests::test_bit_count_boolean ... ok +test function::bitwise::bit_count::tests::test_bit_count_uint32 ... ok +test function::bitwise::bit_count::tests::test_bit_count_uint64 ... ok +test function::bitwise::bit_count::tests::test_bit_count_uint8 ... ok +test function::bitwise::bitwise_not::tests::test_bitwise_not_nullability ... ok +test function::bitwise::bit_get::tests::test_bit_get_nullability_nullable_inputs ... ok +test function::bitwise::bit_get::tests::test_bit_get_nullability_non_nullable_inputs ... ok +test function::datetime::date_add::tests::test_date_add_non_nullable_inputs ... ok +test function::bitwise::bit_shift::tests::test_bit_shift_nullability ... ok +test function::datetime::date_add::tests::test_date_add_nullable_inputs ... ok +test function::datetime::date_sub::tests::test_date_sub_nullability_non_nullable_args ... ok +test function::datetime::date_sub::tests::test_date_sub_nullability_nullable_arg ... ok +test function::datetime::extract::tests::test_hour_return_type ... ok +test function::datetime::extract::tests::test_minute_return_type ... ok +test function::datetime::extract::tests::test_second_return_type ... ok +test function::datetime::last_day::tests::test_last_day_nullability_matches_input ... ok +test function::datetime::extract::tests::test_spark_second ... ok +test function::datetime::extract::tests::test_spark_minute ... ok +test function::datetime::extract::tests::test_spark_hour ... ok +test function::datetime::make_dt_interval::tests::frac_carries_down_to_prev_second_negative ... ok +test function::datetime::make_dt_interval::tests::error_months_overflow_should_be_null ... ok +test function::datetime::make_dt_interval::tests::frac_carries_up_to_next_second_positive ... ok +test function::datetime::make_dt_interval::tests::no_more_than_4_params ... ok +test function::datetime::last_day::tests::test_last_day_scalar_evaluation ... ok +test function::datetime::make_dt_interval::tests::nulls_propagate_per_row ... ok +test function::datetime::make_dt_interval::tests::one_day_minus_24_hours_equals_zero ... ok +test function::datetime::make_dt_interval::tests::one_hour_minus_60_mins_equals_zero ... ok +test function::datetime::make_dt_interval::tests::one_mins_minus_60_secs_equals_zero ... ok +test function::datetime::make_dt_interval::tests::return_field_respects_nullability ... ok +test function::datetime::make_dt_interval::tests::zero_args_returns_zero_duration ... ok +test function::datetime::make_interval::tests::error_min_overflow_should_be_null ... ok +test function::datetime::make_interval::tests::error_days_overflow_should_be_null ... ok +test function::datetime::make_interval::tests::error_months_overflow_should_be_null ... ok +test function::datetime::make_interval::tests::error_sec_overflow_should_be_null ... ok +test function::bitmap::bitmap_count::tests::test_dictionary_encoded_bitmap_count_invoke ... ok +test function::datetime::make_interval::tests::happy_path_all_present_single_row ... ok +test function::datetime::make_interval::tests::negative_components_and_fractional_seconds ... ok +test function::datetime::make_interval::tests::nulls_propagate_per_row ... ok +test function::datetime::make_interval::tests::zero_args_returns_zero_seconds ... ok +test function::datetime::next_day::tests::next_day_is_always_nullable ... ok +test function::hash::crc32::tests::test_crc32_nullability ... ok +test function::hash::sha1::tests::test_sha1_nullability ... ok +test function::bitmap::bitmap_count::tests::test_bitmap_count_invoke ... ok +test function::datetime::next_day::tests::return_type_is_not_used ... ok +test function::map::map_from_arrays::tests::test_map_from_arrays_nullability_and_type ... ok +test function::map::map_from_entries::tests::test_map_from_entries_nullability_matches_input ... ok +test function::math::abs::tests::test_abs_nullability ... ok +test function::math::factorial::test::test_spark_factorial_scalar ... ok +test function::math::factorial::test::test_spark_factorial_array ... ok +test function::math::abs::tests::test_abs_array_ansi_mode ... ok +test function::math::abs::tests::test_abs_array_legacy_mode ... ok +test function::math::hex::test::test_hex_int64 ... ok +test function::math::hex::test::test_dict_values_null ... ok +test function::math::hex::test::test_spark_hex_int64 ... ok +test function::math::hex::test::test_dictionary_hex_binary ... ok +test function::math::hex::test::test_dictionary_hex_utf8 ... ok +test function::math::modulus::test::test_mod_int64 ... ok +test function::math::modulus::test::test_mod_int32 ... ok +test function::math::modulus::test::test_mod_wrong_arg_count ... ok +test function::math::modulus::test::test_mod_scalar ... ok +test function::math::modulus::test::test_mod_zero_division ... ok +test function::math::modulus::test::test_mod_float64 ... ok +test function::math::modulus::test::test_mod_float32 ... ok +test function::math::hex::test::test_dictionary_hex_int64 ... ok +test function::math::modulus::test::test_pmod_wrong_arg_count ... ok +test function::math::modulus::test::test_pmod_zero_division ... ok +test function::math::rint::tests::test_rint_integers ... ok +test function::math::modulus::test::test_pmod_scalar ... ok +test function::math::modulus::test::test_pmod_float64 ... ok +test function::math::modulus::test::test_pmod_negative_divisor ... ok +test function::math::modulus::test::test_pmod_edge_cases ... ok +test function::math::modulus::test::test_pmod_int64 ... ok +test function::math::modulus::test::test_pmod_float32 ... ok +test function::math::rint::tests::test_rint_negative_decimals ... ok +test function::math::modulus::test::test_pmod_int32 ... ok +test function::math::rint::tests::test_rint_null ... ok +test function::math::rint::tests::test_rint_positive_decimals ... ok +test function::math::rint::tests::test_rint_zero ... ok +test function::math::width_bucket::tests::test_width_bucket_duration_us ... ok +test function::math::width_bucket::tests::test_width_bucket_duration_us_equal_bounds ... ok +test function::math::width_bucket::tests::test_width_bucket_f64_basic ... ok +test function::math::width_bucket::tests::test_width_bucket_f64_bounds_inclusive_exclusive_asc ... ok +test function::math::width_bucket::tests::test_width_bucket_f64_bounds_inclusive_exclusive_desc ... ok +test function::math::width_bucket::tests::test_width_bucket_f64_descending_range ... ok +test function::math::width_bucket::tests::test_width_bucket_f64_edge_cases ... ok +test function::math::width_bucket::tests::test_width_bucket_f64_nulls_propagate ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_day_nano_basic ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_day_nano_desc ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_day_nano_desc_inside ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_equal_bounds_is_null ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_invalid_n_is_null ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_mixed_months_and_days_is_null ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_months_only_basic ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_months_only_desc ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_mdn_nulls_propagate ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_ym_basic ... ok +test function::math::width_bucket::tests::test_width_bucket_interval_ym_desc ... ok +test function::math::width_bucket::tests::test_width_bucket_unsupported_type ... ok +test function::math::width_bucket::tests::test_width_bucket_wrong_arg_count ... ok +test function::string::ascii::tests::test_return_field_non_nullable_input ... ok +test function::string::ascii::tests::test_return_field_nullable_input ... ok +test function::string::char::test_char_nullability ... ok +test function::string::concat::tests::test_concat_with_null ... ok +test function::string::concat::tests::test_spark_concat_return_field_non_nullable ... ok +test function::string::concat::tests::test_spark_concat_return_field_nullable ... ok +test function::string::concat::tests::test_concat_basic ... ok +test function::string::elt::tests::elt_utf8_basic ... ok +test function::string::elt::tests::elt_out_of_range_all_null ... ok +test function::string::elt::tests::elt_utf8_returns_utf8 ... ok +test function::string::format_string::tests::test_format_string_nullability ... ok +test function::string::ilike::tests::test_ilike_nullability ... ok +test function::string::elt::tests::elt_int64_basic ... ok +test function::string::length::tests::test_spark_length_nullability ... ok +test function::string::like::tests::test_like_nullability ... ok +test function::string::space::tests::test_spark_space_int32_array ... ok +test function::string::space::tests::test_spark_space_scalar ... ok +test function::string::space::tests::test_spark_space_dictionary ... ok +test function::url::parse_url::tests::test_invalid_arg_count ... ok +test function::url::parse_url::tests::test_non_string_types_error ... ok +test function::url::parse_url::tests::test_parse_malformed_url_returns_error ... ok +test function::string::length::tests::test_functions ... ok +test function::url::parse_url::tests::test_parse_path_root_is_empty_string ... ok +test function::url::parse_url::tests::test_spark_userinfo_and_nulls ... ok +test function::url::parse_url::tests::test_parse_host ... ok +test function::url::parse_url::tests::test_parse_ref_protocol_userinfo_file_authority ... ok +test function::url::parse_url::tests::test_parse_query_no_key_vs_with_key ... ok +test function::url::parse_url::tests::test_spark_utf8_two_args ... ok +test function::url::try_url_decode::tests::test_try_decode_error_handled ... ok +test function::url::parse_url::tests::test_spark_utf8_three_args_query_key ... ok +test function::url::url_decode::tests::test_decode_error ... ok +test function::url::url_decode::tests::test_decode ... ok +test session_state::tests::test_session_state_with_spark_features ... ok +test function::string::like::tests::test_like_invoke ... ok +test function::string::ilike::tests::test_ilike_invoke ... ok + +test result: ok. 163 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running unittests src/lib.rs (target/debug/deps/datafusion_sql-20442edb4c65819d) + +running 67 tests +test expr::identifier::test::test_form_identifier ... ok +test expr::identifier::test::test_generate_schema_search_terms ... ok +test expr::value::tests::test_bigint_to_i256 ... ok +test expr::value::tests::test_parse_decimal ... ok +test expr::tests::test_stack_overflow_64 ... ok +test expr::tests::test_stack_overflow_128 ... ok +test expr::value::tests::test_decode_hex_literal ... ok +test parser::tests::copy_to_multi_options ... ok +test parser::tests::copy_to_partitioned_by ... ok +test expr::tests::test_sql_to_expr_with_alias ... ok +test parser::tests::copy_to_options ... ok +test expr::tests::test_stack_overflow_256 ... ok +test parser::tests::copy_to_table_to_table ... ok +test parser::tests::copy_to_query_to_table ... ok +test parser::tests::explain_copy_to_table_to_table ... ok +test parser::tests::literal ... ok +test parser::tests::literal_with_alias ... ok +test parser::tests::literal_with_alias_and_trailing_tokens ... ok +test parser::tests::literal_with_alias_and_trailing_whitespace ... ok +test parser::tests::literal_with_alias_and_trailing_whitespace_and_token ... ok +test parser::tests::create_external_table ... ok +test parser::tests::test_multistatement ... ok +test parser::tests::test_recursion_limit ... ok +test parser::tests::skip_copy_into_snowflake ... ok +test resolve::tests::resolve_table_references_cte_with_quoted_reference ... ok +test resolve::tests::resolve_table_references_cte_with_quoted_reference_uppercase_normalization_off ... ok +test resolve::tests::resolve_table_references_cte_with_quoted_reference_uppercase_normalization_on ... ok +test resolve::tests::resolve_table_references_cte_with_quoted_reference_normalization_off ... ok +test resolve::tests::resolve_table_references_recursive_cte ... ok +test resolve::tests::resolve_table_references_shadowed_cte ... ok +test unparser::expr::tests::custom_dialect_date32_ast_dtype ... ok +test unparser::expr::tests::custom_dialect_division_operator ... ok +test unparser::expr::tests::custom_dialect_float64_ast_dtype ... ok +test unparser::expr::tests::custom_dialect_use_timestamp_for_date64 ... ok +test unparser::expr::tests::custom_dialect_use_char_for_utf8_cast ... ok +test unparser::expr::tests::custom_dialect_with_timestamp_cast_dtype ... ok +test expr::tests::test_stack_overflow_512 ... ok +test unparser::expr::tests::custom_dialect_without_identifier_quote_style ... ok +test unparser::expr::tests::customer_dialect_support_nulls_first_in_ort ... ok +test unparser::expr::tests::custom_dialect_with_int64_cast_dtype ... ok +test unparser::expr::tests::custom_dialect_with_int32_cast_dtype ... ok +test unparser::expr::tests::custom_dialect_with_identifier_quote_style ... ok +test unparser::expr::tests::test_cast_timestamp_sqlite ... ok +test unparser::expr::tests::test_cast_value_to_dict_expr ... ok +test unparser::expr::tests::test_cast_value_to_binary_expr ... ok +test unparser::expr::tests::custom_dialect_with_date_field_extract_style ... ok +test unparser::expr::tests::test_custom_scalar_overrides_duckdb ... ok +test unparser::expr::tests::test_character_length_scalar_to_expr ... ok +test unparser::expr::tests::test_dictionary_to_sql ... ok +test unparser::expr::tests::test_float_scalar_to_expr ... ok +test unparser::expr::tests::custom_dialect_with_timestamp_cast_dtype_scalar_expr ... ok +test unparser::expr::tests::test_round_scalar_fn_to_expr ... ok +test unparser::expr::tests::test_utf8_view_to_sql ... ok +test utils::tests::test_resolve_positions_to_exprs ... ok +test unparser::expr::tests::test_window_func_support_window_frame ... ok +test unparser::expr::tests::test_timestamp_with_tz_format ... ok +test utils::tests::test_transform_bottom_unnest ... ok +test utils::tests::test_transform_bottom_unnest_recursive ... ok +test utils::tests::test_transform_non_consecutive_unnests ... ok +test unparser::expr::tests::test_from_unixtime ... ok +test unparser::expr::tests::test_interval_scalar_to_expr ... ok +test expr::tests::test_stack_overflow_1024 ... ok +test unparser::expr::tests::test_date_trunc ... ok +test expr::tests::test_stack_overflow_2048 ... ok +test unparser::expr::tests::expr_to_sql_ok ... ok +test expr::tests::test_stack_overflow_4096 ... ok +test expr::tests::test_stack_overflow_8192 ... ok + +test result: ok. 67 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s + + Running tests/sql_integration.rs (target/debug/deps/sql_integration-d84187eb6ffa0226) + +running 449 tests +test cases::collection::test_collect_select_items ... ok +test cases::collection::test_collect_set_exprs ... ok +test cases::diagnostic::test_in_subquery_multiple_columns ... ok +test boolean_literal_in_condition_expression ... ok +test approx_median_window ... ok +test aggregate_with_grouping_sets ... ok +test aggregate_with_cube ... ok +test cases::diagnostic::test_ambiguous_column_suggestion ... ok +test aggregate_with_rollup_with_grouping ... ok +test aggregate_with_rollup ... ok +test cases::diagnostic::test_incompatible_types_binary_arithmetic ... ok +test cases::diagnostic::test_field_not_found_suggestion ... ok +test cases::diagnostic::test_ambiguous_reference ... ok +test cases::diagnostic::test_invalid_function ... ok +test cases::diagnostic::test_unary_op_plus_with_non_column ... ok +test cases::params::test_infer_types_from_predicate ... ok +test cases::params::test_infer_types_from_join ... ok +test cases::params::test_infer_types_from_between_predicate ... ok +test cases::params::test_insert_infer ... ok +test cases::params::test_infer_types_subquery ... ok +test cases::params::test_non_prepare_statement_should_infer_types ... ok +test cases::params::test_prepare_statement_bad_list_idx ... ok +test cases::params::test_prepare_statement_infer_types_from_between_predicate ... ok +test cases::params::test_insert_infer_with_metadata ... ok +test cases::params::test_prepare_statement_infer_types_from_predicate ... ok +test cases::params::test_prepare_statement_insert_infer ... ok +test cases::params::test_prepare_statement_should_infer_types ... ok +test cases::params::test_prepare_statement_infer_types_from_join ... ok +test cases::params::test_prepare_statement_to_plan_data_type ... ok +test cases::params::test_prepare_statement_to_plan_limit ... ok +test cases::params::test_prepare_statement_infer_types_subquery ... ok +test cases::params::test_prepare_statement_to_plan_multi_params ... ok +test cases::params::test_prepare_statement_to_plan_having ... ok +test cases::params::test_prepare_statement_to_plan_no_param_on_value_panic ... ok +test cases::params::test_prepare_statement_to_plan_no_param ... ok +test cases::params::test_prepare_statement_to_plan_one_param ... ok +test cases::params::test_prepare_statement_to_plan_one_param_no_value_panic ... ok +test cases::params::test_prepare_statement_to_plan_one_param_one_value_different_type_panic ... ok +test cases::params::test_prepare_statement_to_plan_panic_no_relation_and_constant_param ... ok +test cases::params::test_prepare_statement_to_plan_panic_is_param - should panic ... ok +test cases::params::test_prepare_statement_to_plan_panic_param_format ... ok +test cases::params::test_prepare_statement_to_plan_panic_prepare_wrong_syntax ... ok +test cases::params::test_prepare_statement_to_plan_panic_param_zero ... ok +test cases::diagnostic::test_missing_non_aggregate_in_group_by ... ok +test cases::params::test_prepare_statement_unknown_hash_param ... ok +test cases::params::test_prepare_statement_unknown_list_param ... ok +test cases::diagnostic::test_union_wrong_number_of_columns ... ok +test cases::diagnostic::test_unqualified_column_not_found ... ok +test cases::params::test_prepare_statement_update_infer ... ok +test cases::params::test_update_infer ... ok +test cases::params::test_prepare_statement_to_plan_params_as_constants ... ok +test cases::diagnostic::test_syntax_error ... ok +test cases::params::test_update_infer_with_metadata ... ok +test cases::diagnostic::test_table_not_found ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_1 ... ok +test cases::plan_to_sql::roundtrip_crossjoin ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_10 ... ok +test cases::diagnostic::test_qualified_column_not_found ... ok +test cases::diagnostic::test_unary_op_plus_with_column ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_16 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_17 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_18 ... ok +test cases::diagnostic::test_scalar_subquery_multiple_columns ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_13 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_2 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_11 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_12 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_21 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_20 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_24 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_19 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_22 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_15 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_25 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_26 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_3 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_28 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_23 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_29 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_35 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_27 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_14 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_32 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_4 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_36 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_34 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_38 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_30 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_31 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_37 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_39 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_41 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_5 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_6 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_42 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_43 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_40 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_7 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_9 ... ok +test cases::plan_to_sql::test_aggregation_without_projection ... ok +test cases::plan_to_sql::test_ilike_filter ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_8 ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_33 ... ok +test cases::plan_to_sql::test_interval_lhs_lt ... ok +test cases::plan_to_sql::test_interval_lhs_eq ... ok +test cases::plan_to_sql::test_like_filter ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_45 ... ok +test cases::plan_to_sql::test_like_filter_with_escape ... ok +test cases::plan_to_sql::test_join_with_no_conditions ... ok +test cases::plan_to_sql::roundtrip_statement_with_dialect_special_char_alias ... ok +test cases::plan_to_sql::test_not_like_filter ... ok +test cases::plan_to_sql::test_not_ilike_filter_with_escape ... ok +test cases::plan_to_sql::test_not_like_filter_with_escape ... ok +test cases::plan_to_sql::test_roundtrip_expr_1 ... ok +test cases::plan_to_sql::test_not_ilike_filter ... ok +test cases::plan_to_sql::test_roundtrip_expr_2 ... ok +test cases::plan_to_sql::test_roundtrip_expr_3 ... ok +test cases::plan_to_sql::test_roundtrip_expr_4 ... ok +test cases::plan_to_sql::test_order_by_to_sql_3 ... ok +test cases::plan_to_sql::test_sort_with_push_down_fetch ... ok +test cases::plan_to_sql::test_complex_order_by_with_grouping ... ok +test cases::plan_to_sql::test_order_by_to_sql_2 ... ok +test cases::plan_to_sql::test_table_references_in_plan_to_sql_1 ... ok +test cases::plan_to_sql::test_table_references_in_plan_to_sql_2 ... ok +test cases::plan_to_sql::test_table_references_in_plan_to_sql_4 ... ok +test cases::plan_to_sql::test_struct_expr2 ... ok +test cases::plan_to_sql::test_table_references_in_plan_to_sql_5 ... ok +test cases::plan_to_sql::test_pretty_roundtrip ... ok +test cases::plan_to_sql::test_table_references_in_plan_to_sql_6 ... ok +test cases::plan_to_sql::test_table_references_in_plan_to_sql_3 ... ok +test cases::plan_to_sql::test_struct_expr3 ... ok +test cases::plan_to_sql::test_table_scan_with_empty_projection_and_filter_postgres ... ok +test cases::plan_to_sql::test_table_scan_with_empty_projection_and_filter_default_dialect ... ok +test cases::plan_to_sql::test_table_scan_with_empty_projection_in_plan_to_sql_1 ... ok +test cases::plan_to_sql::test_table_scan_with_empty_projection_in_plan_to_sql_2 ... ok +test cases::plan_to_sql::test_order_by_to_sql_1 ... ok +test cases::plan_to_sql::test_table_scan_with_empty_projection_in_plan_to_sql_postgres ... ok +test cases::plan_to_sql::test_table_scan_with_empty_projection_in_plan_to_sql_3 ... ok +test cases::plan_to_sql::test_struct_expr ... ok +test cases::plan_to_sql::test_table_scan_with_empty_projection_in_plan_to_sql_default_dialect ... ok +test cases::plan_to_sql::test_table_scan_with_none_projection_in_plan_to_sql_2 ... ok +test cases::plan_to_sql::test_table_scan_with_none_projection_in_plan_to_sql_1 ... ok +test cases::plan_to_sql::test_table_scan_with_none_projection_in_plan_to_sql_3 ... ok +test cases::plan_to_sql::test_unparse_cross_join_with_table_scan_projection ... ok +test cases::plan_to_sql::test_unnest_logical_plan ... ok +test cases::plan_to_sql::test_unnest_to_sql_2 ... ok +test cases::plan_to_sql::test_unparse_left_mark_join ... ok +test cases::plan_to_sql::test_unparse_left_anti_join ... ok +test cases::plan_to_sql::test_unparse_left_semi_join ... ok +test cases::plan_to_sql::test_unparse_extension_to_statement ... ok +test cases::plan_to_sql::test_aggregation_to_sql ... ok +test cases::plan_to_sql::test_unparse_inner_join_with_table_scan_projection ... ok +test cases::plan_to_sql::test_unparse_left_semi_join_with_table_scan_projection ... ok +test cases::plan_to_sql::test_unparse_right_semi_join ... ok +test cases::plan_to_sql::test_unparse_extension_to_sql ... ok +test cases::plan_to_sql::test_unparse_right_anti_join ... ok +test cases::plan_to_sql::test_with_offset0 ... ok +test cases::plan_to_sql::test_unnest_to_sql_1 ... ok +test cases::plan_to_sql::test_without_offset ... ok +test cases::plan_to_sql::test_with_offset95 ... ok +test cast_to_invalid_decimal_type_precision_gt_76 ... ok +test cast_from_subquery ... ok +test cast_to_invalid_decimal_type_precision_0 ... ok +test cast_to_invalid_decimal_type_precision_gt_38 ... ok +test cast_to_invalid_decimal_type_precision_lt_scale ... ok +test cases::plan_to_sql::test_unparse_optimized_multi_union ... ok +test create_external_table_csv_no_schema ... ok +test create_external_table_csv ... ok +test create_external_table_custom ... ok +test create_external_table_parquet ... ok +test create_external_table_parquet_no_schema_sort_order ... ok +test create_external_table_wih_schema ... ok +test create_external_table_parquet_no_schema ... ok +test create_external_table_parquet_sort_order ... ok +test complex_interval_expression_in_projection ... ok +test create_external_table_with_pk ... ok +test create_schema_with_quoted_name ... ok +test create_schema_with_quoted_unnormalized_name ... ok +test cases::plan_to_sql::test_unparse_subquery_alias_with_table_pushdown ... ok +test create_schema_with_unquoted_normalized_name ... ok +test date_plus_interval_in_filter ... ok +test create_external_table_with_compression_type ... ok +test cross_join_not_to_inner_join ... ok +test date_plus_interval_in_projection ... ok +test empty_over ... ok +test empty_over_plus ... ok +test empty_over_dup_with_alias ... ok +test empty_over_dup_with_different_sort ... ok +test cases::plan_to_sql::test_join_with_table_scan_filters ... ok +test cases::plan_to_sql::test_unparse_window ... ok +test cases::plan_to_sql::test_table_scan_alias ... ok +test empty_over_with_alias ... ok +test equijoin_explicit_syntax ... ok +test fetch_clause_is_not_supported ... ok +test empty_over_multiple ... ok +test equijoin_explicit_syntax_3_tables ... ok +test equijoin_with_condition ... ok +test exists_subquery ... ok +test join_on_disjunction_condition ... ok +test hive_aggregate_with_filter ... ok +test group_by_ambiguous_name ... ok +test join_on_complex_condition ... ok +test join_with_aliases ... ok +test join_with_ambiguous_column ... ok +test join_with_using ... ok +test exists_subquery_schema_outer_schema_overlap ... ok +test in_subquery_uncorrelated ... ok +test join_with_table_name ... ok +test full_equijoin_with_conditions ... ok +test left_equijoin_with_conditions ... ok +test natural_left_join ... ok +test negative_interval_plus_interval_in_projection ... ok +test natural_right_join ... ok +test order_by_ambiguous_name ... ok +test not_in_subquery_correlated ... ok +test negative_sum_intervals_in_projection ... ok +test over_order_by_sort_keys_sorting ... ok +test over_order_by_two_sort_keys ... ok +test over_order_by_sort_keys_sorting_global_order_compacting ... ok +test over_order_by_sort_keys_sorting_prefix_compacting ... ok +test over_order_by_with_window_frame_double_end ... ok +test over_partition_by ... ok +test over_order_by ... ok +test order_by_unaliased_name ... ok +test parse_decimals_1 ... ok +test parse_decimals_3 ... ok +test over_partition_by_order_by ... ok +test parse_decimals_2 ... ok +test over_order_by_with_window_frame_single_end ... ok +test over_partition_by_order_by_mix_up ... ok +test over_order_by_with_window_frame_single_end_groups ... ok +test over_partition_by_order_by_mix_up_prefix ... ok +test parse_decimals_4 ... ok +test over_partition_by_order_by_no_dup ... ok +test parse_decimals_6 ... ok +test parse_decimals_5 ... ok +test parse_decimals_7 ... ok +test parse_decimals_8 ... ok +test parse_ident_normalization_1 ... ok +test parse_ident_normalization_2 ... ok +test parse_ident_normalization_3 ... ok +test parse_decimals_9 ... ok +test parse_ident_normalization_5 ... ok +test plan_copy_to ... ok +test parse_ident_normalization_4 ... ok +test parse_ident_normalization_6 ... ok +test plan_commit_transaction_chained ... ok +test plan_create_index ... ok +test plan_commit_transaction ... ok +test plan_create_table_check_constraint ... ok +test parse_ident_normalization_7 ... ok +test plan_create_table_no_pk ... ok +test plan_create_table_with_multi_pk ... ok +test plan_create_table_with_unique ... ok +test plan_delete_quoted_identifier_case_sensitive ... ok +test plan_explain_copy_to_format ... ok +test plan_delete ... ok +test plan_explain_copy_to ... ok +test plan_rollback_transaction ... ok +test plan_insert_no_target_columns ... ok +test plan_create_table_with_pk ... ok +test plan_start_transaction ... ok +test plan_start_transaction_fully_qualified ... ok +test plan_rollback_transaction_chained ... ok +test plan_start_transaction_isolation ... ok +test plan_start_transaction_read_only ... ok +test plan_start_transaction_overly_qualified ... ok +test plan_insert ... ok +test plan_update ... ok +test right_equijoin_with_conditions ... ok +test round_decimal ... ok +test select_aggregate_aliased_with_having_referencing_aggregate_by_its_alias ... ok +test select_aggregate_aliased_with_group_by_with_having_referencing_aggregate_by_its_alias ... ok +test select_aggregate_aliased_with_having_that_reuses_aggregate_but_not_by_its_alias ... ok +test rank_partition_grouping ... ok +test select_7480_1 ... ok +test select_7480_2 ... ok +test scalar_subquery ... ok +test select_aggregate_compounded_with_groupby_column ... ok +test select_aggregate_compound_aliased_with_group_by_with_having_referencing_compound_aggregate_by_its_alias ... ok +test select_aggregate_with_group_by_with_having_referencing_column_not_in_group_by ... ok +test select_aggregate_with_group_by_with_having_and_where ... ok +test scalar_subquery_reference_outer_field ... ok +test select_aggregate_with_group_by_with_having ... ok +test select_aggregate_with_group_by_with_having_and_where_filtering_on_aggregate_column ... ok +test select_aggregate_with_group_by_with_having_that_reuses_aggregate_multiple_times ... ok +test select_aggregate_with_group_by_with_having_using_aggregate_not_in_select ... ok +test select_aggregate_with_group_by_with_having_using_columns_with_and_without_their_aliases ... ok +test select_aggregate_with_having_referencing_column_not_in_select ... ok +test select_aggregate_with_group_by_with_having_using_column_by_alias ... ok +test select_aggregate_with_group_by_with_having_that_reuses_aggregate ... ok +test select_aggregate_with_having_with_aggregate_not_in_select ... ok +test select_aggregate_with_non_column_inner_expression_with_groupby ... ok +test select_aliased_scalar_func ... ok +test select_aggregate_with_group_by_with_having_using_derived_column_aggregate_not_in_select ... ok +test select_aggregate_with_group_by_with_having_using_count_star_not_in_select ... ok +test select_approx_median ... ok +test select_between ... ok +test select_binary_expr ... ok +test select_binary_expr_nested ... ok +test select_between_negated ... ok +test select_aggregate_with_having_that_reuses_aggregate ... ok +test select_column_does_not_exist ... ok +test select_filter_cannot_use_alias ... ok +test select_count_column ... ok +test select_filter_column_does_not_exist ... ok +test select_group_by ... ok +test select_count_one ... ok +test select_group_by_columns_not_in_select ... ok +test select_all_boolean_operators ... ok +test select_from_typed_string_values ... ok +test select_compound_filter ... ok +test cases::plan_to_sql::test_table_scan_pushdown ... ok +test select_group_by_needs_projection ... ok +test select_interval_out_of_range ... ok +test select_groupby_orderby_aggregate_on_non_selected_column ... ok +test select_group_by_count_star ... ok +test select_groupby_orderby_aggregate_on_non_selected_column_original_issue ... ok +test select_multibyte_column ... ok +test select_neg_filter ... ok +test select_groupby_orderby_multiple_aggregates_on_non_selected_columns ... ok +test select_order_by_desc ... ok +test select_no_relation ... ok +test select_order_by_index_of_0 ... ok +test select_nested_with_filters ... ok +test select_order_by_index ... ok +test select_order_by_index_oob ... ok +test select_partially_qualified_column ... ok +test select_nested ... ok +test select_repeated_column ... ok +test select_order_by_with_cast ... ok +test select_order_by_multiple_index ... ok +test select_order_by_nulls_last ... ok +test select_scalar_func_with_literal_no_relation ... ok +test select_simple_aggregate ... ok +test select_simple_aggregate_and_nested_groupby_column ... ok +test select_scalar_func ... ok +test select_simple_aggregate_repeated_aggregate ... ok +test select_simple_aggregate_nested_in_binary_expr_with_groupby ... ok +test select_simple_aggregate_column_does_not_exist ... ok +test select_simple_aggregate_repeated_aggregate_with_repeated_aliases ... ok +test select_simple_aggregate_with_groupby_aggregate_repeated ... ok +test select_simple_aggregate_repeated_aggregate_with_unique_aliases ... ok +test select_simple_aggregate_repeated_aggregate_with_single_alias ... ok +test select_simple_aggregate_with_groupby_and_column_in_group_by_does_not_exist ... ok +test select_simple_aggregate_with_groupby_and_column_in_aggregate_does_not_exist ... ok +test select_simple_aggregate_with_groupby ... ok +test select_simple_aggregate_with_groupby_aggregate_repeated_and_one_has_alias ... ok +test select_simple_aggregate_with_groupby_can_use_alias ... ok +test select_simple_aggregate_with_groupby_and_column_is_in_aggregate_and_groupby ... ok +test select_simple_aggregate_with_groupby_non_column_expression_and_its_column_selected ... ok +test select_simple_aggregate_with_groupby_column_unselected ... ok +test select_simple_aggregate_with_groupby_non_column_expression_nested_and_not_resolvable ... ok +test select_simple_aggregate_with_groupby_non_column_expression_nested_and_resolvable ... ok +test select_simple_aggregate_with_groupby_non_column_expression_unselected ... ok +test select_simple_aggregate_with_groupby_can_use_positions ... ok +test select_simple_aggregate_with_groupby_with_aliases ... ok +test select_simple_aggregate_with_groupby_with_aliases_repeated ... ok +test select_simple_aggregate_with_groupby_position_out_of_range ... ok +test select_where_compound_identifiers ... ok +test select_simple_filter ... ok +test select_typed_date_string ... ok +test select_typed_time_string ... ok +test select_simple_aggregate_with_groupby_non_column_expression_selected_and_resolvable ... ok +test select_where_with_negative_operator ... ok +test select_where_nullif_division ... ok +test select_groupby_orderby ... ok +test select_where_with_positive_operator ... ok +test select_with_having ... ok +test select_with_having_referencing_column_nested_in_select_expression ... ok +test select_with_having_referencing_column_not_in_select ... ok +test select_with_ambiguous_column ... ok +test select_with_having_with_aggregate_not_in_select ... ok +test select_with_having_refers_to_invalid_column ... ok +test table_with_column_alias_number_cols ... ok +test test_ambiguous_column_references_in_on_join ... ok +test select_with_order_by ... ok +test test_constant_expr_eq_join ... ok +test test_avoid_add_alias ... ok +test table_with_column_alias ... ok +test test_double_quoted_literal_string ... ok +test test_duplicated_left_join_key_inner_join ... ok +test test_custom_type_plan ... ok +test test_ambiguous_column_references_with_in_using_join ... ok +test test_error_message_invalid_scalar_function_signature ... ok +test test_distribute_by ... ok +test test_error_message_invalid_window_aggregate_function_signature ... ok +test test_date_filter ... ok +test test_error_message_invalid_aggregate_function_signature ... ok +test test_insert_schema_errors::case_1_duplicate_columns ... ok +test test_insert_schema_errors::case_2_non_existing_column ... ok +test test_duplicated_right_join_key_inner_join ... ok +test test_error_message_invalid_window_function_signature ... ok +test test_insert_schema_errors::case_3_target_column_count_mismatch ... ok +test test_inner_join_with_cast_key ... ok +test test_insert_schema_errors::case_6_placeholder_type_unresolved ... ok +test test_insert_schema_errors::case_4_source_column_count_mismatch ... ok +test test_insert_schema_errors::case_5_extra_placeholder ... ok +test test_int_decimal_default ... ok +test test_field_not_found_window_function ... ok +test test_no_functions_registered ... ok +test test_left_expr_eq_join ... ok +test test_int_decimal_no_scale ... ok +test test_no_substring_registered_alt_syntax ... ok +test test_offset_after_limit ... ok +test test_no_substring_registered ... ok +test test_offset_no_limit ... ok +test test_multiple_column_expr_eq_join ... ok +test test_one_side_constant_full_join ... ok +test test_real_f32 ... ok +test test_parse_quoted_column_name_with_at_sign ... ok +test test_offset_before_limit ... ok +test test_right_left_expr_eq_join ... ok +test test_select_order_by ... ok +test test_select_join_key_inner_join ... ok +test test_select_distinct_order_by ... ok +test test_multi_grouping_sets ... ok +test test_parse_escaped_string_literal_value ... ok +test test_noneq_with_filter_join ... ok +test test_select_qualify_without_window_function ... ok +test test_select_unsupported_syntax_errors::case_2_select_lateral_view_unsupported ... ok +test test_select_unsupported_syntax_errors::case_1_select_cluster_by_unsupported ... ok +test test_right_expr_eq_join ... ok +test test_select_qualify_basic ... ok +test test_select_unsupported_syntax_errors::case_3_select_top_unsupported ... ok +test test_select_qualify_aggregate_invalid_column_reference ... ok +test test_select_unsupported_syntax_errors::case_4_select_sort_by_unsupported ... ok +test test_select_qualify_aggregate_reference ... ok +test test_tinyint ... ok +test test_select_qualify_complex_condition ... ok +test test_timestamp_filter ... ok +test test_single_column_expr_eq_join ... ok +test test_variable_identifier ... ok +test test_select_qualify_aggregate_reference_within_window_function ... ok +test test_sum_aggregate ... ok +test try_cast_from_aggregation ... ok +test union ... ok +test union_all ... ok +test union_all_by_name_same_column_names ... ok +test union_by_name_different_columns ... ok +test test_zero_offset_with_limit ... ok +test within_group_rejected_for_non_ordered_set_udaf ... ok +test union_all_by_name_different_columns ... ok +test update_column_does_not_exist::case_1_missing_assignment_target ... ok +test update_column_does_not_exist::case_2_missing_assignment_expression ... ok +test update_column_does_not_exist::case_3_missing_selection_expression ... ok +test union_by_name_same_column_names ... ok +test test_using_join_wildcard_schema ... ok +test cases::plan_to_sql::roundtrip_statement ... ok + +test result: ok. 449 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.15s + + Running unittests src/lib.rs (target/debug/deps/datafusion_sqllogictest-e2c6598e3a498544) + +running 2 tests +test util::tests::ignore_marker_does_not_skip_leading_text ... ok +test engines::conversion::tests::test_big_decimal_to_str ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running bin/sqllogictests.rs (target/debug/deps/sqllogictests-f97f284324355eff) + Running unittests src/lib.rs (target/debug/deps/datafusion_substrait-55ca4e51f26731e4) + +running 18 tests +test logical_plan::consumer::utils::tests::rename_schema ... ok +test logical_plan::producer::expr::field_reference::tests::to_field_reference ... ok +test logical_plan::producer::expr::cast::tests::fold_cast_null ... ok +test logical_plan::producer::expr::tests::extended_expressions ... ok +test logical_plan::producer::expr::tests::invalid_extended_expression ... ok +test logical_plan::consumer::expr::literal::tests::interval_compound_different_precision ... ok +test logical_plan::consumer::expr::scalar_function::tests::test_substrait_to_df_name_mapping ... ok +test logical_plan::consumer::expr::scalar_function::tests::test_like_match_conversion ... ok +test logical_plan::consumer::expr::tests::window_function_with_count ... ok +test logical_plan::producer::types::tests::named_struct_names ... ok +test logical_plan::consumer::expr::tests::window_function_with_range_unit_and_no_order_by ... ok +test logical_plan::producer::types::tests::round_trip_types ... ok +test logical_plan::producer::expr::literal::tests::round_trip_literals ... ok +test logical_plan::consumer::expr::scalar_function::tests::test_binary_op_large_argument_list ... ok +test logical_plan::consumer::expr::scalar_function::tests::arg_list_to_binary_op_tree_2_args ... ok +test logical_plan::consumer::expr::scalar_function::tests::arg_list_to_binary_op_tree_1_arg ... ok +test logical_plan::consumer::expr::scalar_function::tests::arg_list_to_binary_op_tree_4_args ... ok +test logical_plan::consumer::expr::scalar_function::tests::arg_list_to_binary_op_tree_3_args ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s + + Running tests/substrait_integration.rs (target/debug/deps/substrait_integration-92b27ab8b32130d8) + +running 186 tests +test cases::builtin_expr_semantics_tests::tests::test_and_not_semantics ... ok +test cases::builtin_expr_semantics_tests::tests::test_logb_semantics ... ok +test cases::builtin_expr_semantics_tests::tests::test_xor_semantics ... ok +test cases::consumer_integration::tests::test_select_count_from_select_1 ... ok +test cases::consumer_integration::tests::test_multiple_joins ... ok +test cases::consumer_integration::tests::test_built_in_binary_exprs_for_xor ... ok +test cases::consumer_integration::tests::test_expressions_in_virtual_table ... ok +test cases::consumer_integration::tests::test_between_expr ... ok +test cases::consumer_integration::tests::test_built_in_binary_exprs_for_and_not ... ok +test cases::consumer_integration::tests::test_logb_expr ... ok +test cases::consumer_integration::tests::test_select_window_count ... ok +test cases::consumer_integration::tests::test_join_with_expression_key ... ok +test cases::consumer_integration::tests::test_multiple_unions ... ok +test cases::consumer_integration::tests::tpch_test_07 ... ignored +test cases::consumer_integration::tests::tpch_test_08 ... ignored +test cases::consumer_integration::tests::tpch_test_09 ... ignored +test cases::aggregation_tests::tests::one_grouping_set ... ok +test cases::aggregation_tests::tests::no_grouping_set ... ok +test cases::consumer_integration::tests::tpch_test_15 ... ignored +test cases::consumer_integration::tests::tpch_test_13 ... ok +test cases::consumer_integration::tests::tpch_test_17 ... ignored +test cases::consumer_integration::tests::tpch_test_06 ... ok +test cases::consumer_integration::tests::tpch_test_14 ... ok +test cases::consumer_integration::tests::tpch_test_01 ... ok +test cases::consumer_integration::tests::tpch_test_04 ... ok +test cases::consumer_integration::tests::tpch_test_12 ... ok +test cases::consumer_integration::tests::tpch_test_03 ... ok +test cases::emit_kind_tests::tests::handle_emit_as_project ... ok +test cases::consumer_integration::tests::tpch_test_16 ... ok +test cases::consumer_integration::tests::tpch_test_05 ... ok +test cases::function_test::tests::contains_function_test ... ok +test cases::consumer_integration::tests::tpch_test_10 ... ok +test cases::consumer_integration::tests::tpch_test_11 ... ok +test cases::emit_kind_tests::tests::project_respects_direct_emit_kind ... ok +test cases::logical_plans::tests::non_nullable_lists ... ok +test cases::logical_plans::tests::double_window_function ... ok +test cases::logical_plans::tests::double_window_function_distinct_windows ... ok +test cases::consumer_integration::tests::tpch_test_19 ... ok +test cases::logical_plans::tests::scalar_function_compound_signature ... ok +test cases::logical_plans::tests::multilayer_aggregate ... ok +test cases::logical_plans::tests::window_function_compound_signature ... ok +test cases::consumer_integration::tests::tpch_test_18 ... ok +test cases::logical_plans::tests::null_literal_before_and_after_joins ... ok +test cases::consumer_integration::tests::tpch_test_20 ... ok +test cases::consumer_integration::tests::tpch_test_02 ... ok +test cases::roundtrip_logical_plan::aggregate_identical_grouping_expressions ... ok +test cases::emit_kind_tests::tests::handle_emit_as_project_without_volatile_exprs ... ok +test cases::emit_kind_tests::tests::handle_emit_as_project_with_volatile_expr ... ok +test cases::roundtrip_logical_plan::aggregate_wo_projection_consume ... ok +test cases::consumer_integration::tests::tpch_test_21 ... ok +test cases::roundtrip_logical_plan::aggregate_grouping_rollup ... ok +test cases::roundtrip_logical_plan::aggregate_wo_projection_group_expression_ref_consume ... ok +test cases::roundtrip_logical_plan::aggregate_grouping_cube ... ok +test cases::roundtrip_logical_plan::aggregate_case ... ok +test cases::consumer_integration::tests::tpch_test_22 ... ok +test cases::roundtrip_logical_plan::aggregate_wo_projection_sorted_consume ... ok +test cases::roundtrip_logical_plan::between_integers ... ok +test cases::roundtrip_logical_plan::extension_logical_plan ... ok +test cases::roundtrip_logical_plan::duplicate_column ... ok +test cases::roundtrip_logical_plan::inner_join ... ok +test cases::roundtrip_logical_plan::cast_decimal_to_int ... ok +test cases::roundtrip_logical_plan::aggregate_grouping_sets ... ok +test cases::roundtrip_logical_plan::aggregate_multiple_keys ... ok +test cases::roundtrip_logical_plan::decimal_literal ... ok +test cases::roundtrip_logical_plan::case_without_base_expression ... ok +test cases::roundtrip_logical_plan::multiset_intersect_all_consume ... ok +test cases::roundtrip_logical_plan::case_with_base_expression ... ok +test cases::roundtrip_logical_plan::implicit_cast ... ok +test cases::roundtrip_logical_plan::multilayer_aggregate ... ok +test cases::roundtrip_logical_plan::not_between_integers ... ok +test cases::roundtrip_logical_plan::aggregate_distinct_with_having ... ok +test cases::roundtrip_logical_plan::multiset_intersect_consume ... ok +test cases::roundtrip_logical_plan::primary_except_consume ... ok +test cases::roundtrip_logical_plan::primary_except_all_consume ... ok +test cases::roundtrip_logical_plan::primary_intersect_consume ... ok +test cases::roundtrip_logical_plan::all_type_literal ... ok +test cases::roundtrip_logical_plan::null_decimal_literal ... ok +test cases::roundtrip_logical_plan::roundtrip_empty_relation_no_rows ... ok +test cases::roundtrip_logical_plan::qualified_schema_table_reference ... ok +test cases::roundtrip_logical_plan::qualified_catalog_schema_table_reference ... ok +test cases::roundtrip_logical_plan::roundtrip_empty_relation_with_schema ... ok +test cases::roundtrip_logical_plan::roundtrip_exists_filter ... ok +test cases::roundtrip_logical_plan::new_test_grammar ... ok +test cases::roundtrip_logical_plan::roundtrip_ilike ... ok +test cases::roundtrip_logical_plan::roundtrip_cross_join ... ok +test cases::roundtrip_logical_plan::roundtrip_inlist_2 ... ok +test cases::roundtrip_logical_plan::roundtrip_inlist_1 ... ok +test cases::roundtrip_logical_plan::roundtrip_inlist_5 ... ok +test cases::roundtrip_logical_plan::roundtrip_inlist_4 ... ok +test cases::roundtrip_logical_plan::roundtrip_inlist_3 ... ok +test cases::roundtrip_logical_plan::roundtrip_is_not_false ... ok +test cases::roundtrip_logical_plan::roundtrip_is_not_true ... ok +test cases::roundtrip_logical_plan::roundtrip_inner_join ... ok +test cases::roundtrip_logical_plan::roundtrip_aggregate_udf ... ok +test cases::roundtrip_logical_plan::roundtrip_is_false ... ok +test cases::roundtrip_logical_plan::roundtrip_is_unknown ... ok +test cases::roundtrip_logical_plan::roundtrip_is_true ... ok +test cases::roundtrip_logical_plan::roundtrip_literal_renamed_struct ... ok +test cases::roundtrip_logical_plan::roundtrip_literal_named_struct ... ok +test cases::roundtrip_logical_plan::roundtrip_literal_without_from ... ok +test cases::roundtrip_logical_plan::roundtrip_is_not_unknown ... ok +test cases::roundtrip_logical_plan::roundtrip_literal_struct ... ok +test cases::roundtrip_logical_plan::roundtrip_like ... ok +test cases::roundtrip_logical_plan::roundtrip_literal_list ... ok +test cases::roundtrip_logical_plan::roundtrip_repartition_roundrobin ... ok +test cases::roundtrip_logical_plan::roundtrip_modulus ... ok +test cases::roundtrip_logical_plan::roundtrip_left_join ... ok +test cases::roundtrip_logical_plan::roundtrip_repartition_hash ... ok +test cases::roundtrip_logical_plan::roundtrip_not ... ok +test cases::roundtrip_logical_plan::roundtrip_negative ... ok +test cases::roundtrip_logical_plan::roundtrip_not_exists_filter_left_anti_join ... ok +test cases::roundtrip_logical_plan::roundtrip_right_anti_join ... ok +test cases::roundtrip_logical_plan::roundtrip_read_filter ... ok +test cases::roundtrip_logical_plan::roundtrip_set_comparison_all_substrait ... ok +test cases::roundtrip_logical_plan::roundtrip_non_equi_inner_join ... ok +test cases::roundtrip_logical_plan::roundtrip_outer_join ... ok +test cases::roundtrip_logical_plan::roundtrip_set_comparison_any_substrait ... ok +test cases::roundtrip_logical_plan::roundtrip_right_semi_join ... ok +test cases::roundtrip_logical_plan::roundtrip_non_equi_join ... ok +test cases::roundtrip_logical_plan::roundtrip_subquery_with_empty_relation ... ok +test cases::roundtrip_logical_plan::roundtrip_values_empty_relation ... ok +test cases::roundtrip_logical_plan::roundtrip_values ... ok +test cases::roundtrip_logical_plan::roundtrip_values_no_columns ... ok +test cases::roundtrip_logical_plan::roundtrip_values_with_scalar_function ... ok +test cases::roundtrip_logical_plan::roundtrip_values_duplicate_column_join ... ok +test cases::roundtrip_logical_plan::roundtrip_union_all ... ok +test cases::roundtrip_logical_plan::scalar_function_is_nan_mapping ... ok +test cases::roundtrip_logical_plan::roundtrip_right_join ... ok +test cases::roundtrip_logical_plan::roundtrip_window_udf ... ok +test cases::roundtrip_logical_plan::select_distinct_two_fields ... ok +test cases::roundtrip_logical_plan::roundtrip_union ... ok +test cases::roundtrip_logical_plan::roundtrip_self_implicit_cross_join ... ok +test cases::roundtrip_logical_plan::select_with_alias ... ok +test cases::roundtrip_logical_plan::roundtrip_union2 ... ok +test cases::roundtrip_logical_plan::select_with_filter_bool_expr ... ok +test cases::roundtrip_logical_plan::select_with_filter ... ok +test cases::roundtrip_logical_plan::select_with_filter_date ... ok +test cases::roundtrip_logical_plan::select_with_filter_sort_limit ... ok +test cases::roundtrip_logical_plan::self_join_introduces_aliases ... ok +test cases::roundtrip_logical_plan::select_with_reused_functions ... ok +test cases::roundtrip_logical_plan::self_referential_except_all ... ok +test cases::roundtrip_logical_plan::select_without_limit ... ok +test cases::roundtrip_logical_plan::self_referential_except ... ok +test cases::roundtrip_logical_plan::select_with_limit ... ok +test cases::roundtrip_logical_plan::self_referential_intersect_all ... ok +test cases::roundtrip_logical_plan::self_referential_intersect ... ok +test cases::roundtrip_logical_plan::select_with_filter_sort_limit_offset ... ok +test cases::roundtrip_logical_plan::simple_alias ... ok +test cases::roundtrip_logical_plan::simple_distinct ... ok +test cases::roundtrip_logical_plan::simple_intersect_consume ... ok +test cases::roundtrip_logical_plan::roundtrip_self_join ... ok +test cases::roundtrip_logical_plan::select_with_limit_offset ... ok +test cases::roundtrip_logical_plan::simple_scalar_function_is_not_null ... ok +test cases::roundtrip_logical_plan::simple_scalar_function_is_null ... ok +test cases::roundtrip_logical_plan::simple_scalar_function_isnan ... ok +test cases::roundtrip_logical_plan::simple_scalar_function_abs ... ok +test cases::roundtrip_logical_plan::simple_scalar_function_substr ... ok +test cases::roundtrip_logical_plan::simple_select ... ok +test cases::roundtrip_logical_plan::simple_aggregate ... ok +test cases::roundtrip_logical_plan::simple_scalar_function_pow ... ok +test cases::roundtrip_logical_plan::try_cast_decimal_to_string ... ok +test cases::roundtrip_logical_plan::u32_literal ... ok +test cases::roundtrip_physical_plan::simple_select_alltypes ... ignored, This test is failing because the translation of the substrait plan to the physical plan is not implemented yet +test cases::roundtrip_physical_plan::parquet_exec ... ok +test cases::roundtrip_physical_plan::wildcard_select_alltypes ... ignored, This test is failing because the translation of the substrait plan to the physical plan is not implemented yet +test cases::roundtrip_logical_plan::two_table_alias ... ok +test cases::roundtrip_logical_plan::try_cast_decimal_to_int ... ok +test cases::roundtrip_logical_plan::union_distinct_consume ... ok +test cases::roundtrip_logical_plan::wildcard_select ... ok +test cases::serialize::tests::include_remaps_for_projects ... ok +test cases::roundtrip_logical_plan::simple_window_function ... ok +test cases::serialize::tests::include_remaps_for_windows ... ok +test cases::serialize::tests::table_scan_without_projection ... ok +test cases::substrait_validations::tests::schema_compatibility::ensure_schema_match_exact ... ok +test cases::roundtrip_logical_plan::roundtrip_arithmetic_ops ... ok +test cases::substrait_validations::tests::schema_compatibility::ensure_schema_match_not_subset ... ok +test cases::roundtrip_physical_plan::wildcard_select ... ok +test cases::roundtrip_physical_plan::simple_select ... ok +test cases::substrait_validations::tests::schema_compatibility::reject_plans_with_incompatible_field_types ... ok +test cases::substrait_validations::tests::schema_compatibility::ensure_schema_match_subset_with_mask ... ok +test cases::substrait_validations::tests::schema_compatibility::ensure_schema_match_subset ... ok +test cases::serialize::tests::serialize_to_file ... ok +test cases::serialize::tests::serialize_simple_select ... ok +test cases::roundtrip_logical_plan::simple_intersect ... ok +test cases::roundtrip_logical_plan::simple_intersect_table_reuse ... ok +test cases::roundtrip_logical_plan::window_with_rows ... ok + +test result: ok. 179 passed; 0 failed; 7 ignored; 0 measured; 0 filtered out; finished in 0.25s + + Running tests/utils.rs (target/debug/deps/utils-7fe518b893f9a26a) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/datafusion_wasmtest-b73ba71f6188e076) + +running 6 tests +test test::test_parquet_write ... ok +test test::basic_execute ... ok +test test::basic_df_function_execute ... ok +test test::test_parquet_read_and_write ... ok +test test::test_basic_aggregate ... ok +test test::test_csv_read_xz_compressed ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running unittests src/lib.rs (target/debug/deps/ffi_example_table_provider-cd5a1e6a7a067f4f) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/ffi_module_interface-1dc0542c106ae84d) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/main.rs (target/debug/deps/ffi_module_loader-e326cef216caa301) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/main.rs (target/debug/deps/gen-49bf5feff41f54a4) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/main.rs (target/debug/deps/gen_common-5c8c8b0c3eb741f4) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running unittests src/lib.rs (target/debug/deps/test_utils-d9178fcff50f8271) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion + +running 229 tests +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::collect (line 1447) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame (line 185) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::drop_columns (line 438) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::cache (line 2374) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::distinct (line 902) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::collect_partitioned (line 1586) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::count (line 1406) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::except (line 1886) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::distinct_on (line 938) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::except_distinct (line 1926) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::aggregate (line 606) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::from_columns (line 2547) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::execute_stream_partitioned (line 1608) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::execute_stream (line 1558) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::fill_null (line 2425) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::explain (line 1719) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::filter (line 566) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::explain_with_options (line 1748) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::find_qualified_columns (line 2509) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::intersect (line 1810) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::intersect_distinct (line 1848) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::join (line 1247) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::registry (line 1790) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::limit (line 698) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::repartition (line 1365) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::parse_sql_expr (line 270) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::join_on (line 1309) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::schema (line 1639) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::select (line 386) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::to_string (line 1490) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::select_columns (line 305) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::show (line 1469) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::show_limit (line 1530) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::select_exprs (line 357) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::unnest_columns (line 508) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::union_by_name (line 779) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::with_column_renamed (line 2235) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::union_by_name_distinct (line 865) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::with_column (line 2159) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::sort (line 1194) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::union_distinct (line 823) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::union (line 737) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::dataframe (line 2583) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext (line 239) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext::create_physical_expr (line 788) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::write_json (line 2089) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext::into_state_builder (line 440) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext::parse_memory_limit (line 1243) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::with_param_values (line 2307) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::write_csv (line 2015) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext::parse_sql_expr (line 660) ... ok +test datafusion/core/src/execution/context/csv.rs - execution::context::csv::SessionContext::read_csv (line 33) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext::register_object_store (line 508) ... ok +test datafusion/core/src/dataframe/parquet.rs - dataframe::parquet::DataFrame::write_parquet (line 36) ... ok +test datafusion/core/src/execution/session_state.rs - execution::session_state::SessionState (line 98) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext::sql_with_options (line 626) ... ok +test datafusion/core/src/execution/session_state.rs - execution::session_state::SessionState (line 109) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext::sql (line 599) ... ok +test datafusion/core/src/execution/session_state.rs - execution::session_state::SessionStateBuilder::new_with_default_features (line 1143) ... ok +test datafusion/core/src/execution/session_state.rs - execution::session_state::SessionStateBuilder::with_object_store (line 1404) ... ok +test datafusion/core/src/lib.rs - contributor_guide_api_health (line 1259) ... ok +test datafusion/core/src/lib.rs - library_user_guide_catalogs (line 1181) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext (line 207) ... ok +test datafusion/core/src/lib.rs - library_user_guide_catalogs (line 1166) ... ok +test datafusion/core/src/lib.rs - library_user_guide_building_logical_plans (line 1154) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext (line 174) ... ok +test datafusion/core/src/lib.rs - library_user_guide_building_logical_plans (line 1227) ... ok +test datafusion/core/src/lib.rs - library_user_guide_building_logical_plans (line 1276) ... ok +test datafusion/core/src/lib.rs - library_user_guide_catalogs (line 1238) ... ok +test datafusion/core/src/lib.rs - library_user_guide_catalogs (line 1353) ... ok +test datafusion/core/src/lib.rs - library_user_guide_catalogs (line 1407) ... ok +test datafusion/core/src/lib.rs - library_user_guide_custom_table_providers (line 1177) ... ok +test datafusion/core/src/lib.rs - library_user_guide_catalogs (line 1326) ... ok +test datafusion/core/src/lib.rs - library_user_guide_custom_table_providers (line 1300) ... ok +test datafusion/core/src/execution/context/mod.rs - execution::context::SessionContext::enable_url_table (line 387) ... ok +test datafusion/core/src/lib.rs - library_user_guide_custom_table_providers (line 1493) ... ok +test datafusion/core/src/lib.rs - library_user_guide_extending_operators (line 1168) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_extending_operators (line 1184) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_dataframe_api (line 1203) ... ok +test datafusion/core/src/lib.rs - library_user_guide_dataframe_api (line 1381) ... ok +test datafusion/core/src/lib.rs - library_user_guide_dataframe_api (line 1238) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1170) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1311) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1335) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1233) ... ok +test datafusion/core/src/lib.rs - (line 126) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1373) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1473) ... ok +test datafusion/core/src/lib.rs - (line 81) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1716) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1795) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1576) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1418) ... ok +test datafusion/core/src/lib.rs - library_user_guide_dataframe_api (line 1292) ... ok +test datafusion/core/src/lib.rs - library_user_guide_dataframe_api (line 1417) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1868) ... ok +test datafusion/core/src/lib.rs - library_user_guide_dataframe_api (line 1395) ... ok +test datafusion/core/src/lib.rs - library_user_guide_dataframe_api (line 1343) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 1945) ... ok +test datafusion/core/src/lib.rs - library_user_guide_dataframe_api (line 1312) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 2239) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 2143) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 2499) ... ok +test datafusion/core/src/lib.rs - library_user_guide_query_optimizer (line 1252) ... ok +test datafusion/core/src/lib.rs - library_user_guide_query_optimizer (line 1206) ... ok +test datafusion/core/src/lib.rs - library_user_guide_query_optimizer (line 1281) ... ok +test datafusion/core/src/lib.rs - library_user_guide_query_optimizer (line 1418) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 2619) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 2540) ... ok +test datafusion/core/src/lib.rs - library_user_guide_query_optimizer (line 1437) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1226) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1235) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1268) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1281) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1292) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1305) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1324) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1331) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1357) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1365) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1392) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1403) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1418) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1427) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1528) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1537) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1685) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1714) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1761) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1774) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1789) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1796) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1819) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1832) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1908) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1915) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1926) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1933) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1950) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1958) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 1968) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2022) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2042) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2078) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2228) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2235) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2259) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2322) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_query_optimizer (line 1472) ... ok +test datafusion/core/src/lib.rs - library_user_guide_query_optimizer (line 1635) ... ok +test datafusion/core/src/lib.rs - library_user_guide_query_optimizer (line 1385) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2457) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2463) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_sql_api (line 1290) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2339) ... ok +test datafusion/core/src/lib.rs - library_user_guide_sql_api (line 1339) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2434) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2417) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2495) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2630) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2636) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2666) ... ignored +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 2346) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2564) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2503) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2520) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2537) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2601) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2704) ... ok +test datafusion/core/src/lib.rs - library_user_guide_sql_api (line 1245) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2737) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2745) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2716) ... ok +test datafusion/core/src/lib.rs - library_user_guide_sql_api (line 1350) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2814) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2859) ... ok +test datafusion/core/src/lib.rs - library_user_guide_functions_adding_udfs (line 2024) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2767) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2947) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2893) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2871) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2969) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2910) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3048) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 2922) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3230) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3172) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3147) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3219) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3181) ... ok +test datafusion/core/src/lib.rs - library_user_guide_sql_api (line 1213) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3259) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3279) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3325) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3336) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3377) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3355) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3476) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3452) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3488) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3510) ... ok +test datafusion/core/src/lib.rs - library_user_guide_upgrading (line 3464) ... ok +test datafusion/core/src/lib.rs - library_user_guide_working_with_exprs (line 1257) ... ok +test datafusion/core/src/lib.rs - library_user_guide_working_with_exprs (line 1347) ... ok +test datafusion/core/src/lib.rs - library_user_guide_working_with_exprs (line 1317) ... ok +test datafusion/core/src/lib.rs - user_guide_arrow_introduction (line 1043) ... ok +test datafusion/core/src/lib.rs - library_user_guide_working_with_exprs (line 1522) ... ok +test datafusion/core/src/lib.rs - user_guide_arrow_introduction (line 1092) ... ok +test datafusion/core/src/lib.rs - user_guide_configs (line 981) ... ok +test datafusion/core/src/lib.rs - user_guide_arrow_introduction (line 1058) ... ok +test datafusion/core/src/lib.rs - user_guide_arrow_introduction (line 1026) ... ok +test datafusion/core/src/lib.rs - library_user_guide_working_with_exprs (line 1408) ... ok +test datafusion/core/src/lib.rs - user_guide_arrow_introduction (line 1115) ... ok +test datafusion/core/src/lib.rs - user_guide_crate_configuration (line 1137) ... ok +test datafusion/core/src/lib.rs - user_guide_crate_configuration (line 1166) ... ok +test datafusion/core/src/lib.rs - user_guide_dataframe (line 1005) ... ok +test datafusion/core/src/lib.rs - user_guide_example_usage (line 1064) ... ok +test datafusion/core/src/lib.rs - user_guide_expressions (line 1002) ... ok +test datafusion/core/src/lib.rs - user_guide_dataframe (line 1013) ... ok +test datafusion/core/src/prelude.rs - prelude (line 24) ... ok +test datafusion/core/src/lib.rs - user_guide_example_usage (line 1023) ... ok +test datafusion/core/src/lib.rs - user_guide_example_usage (line 1000) ... ok +test datafusion/core/src/lib.rs - user_guide_example_usage (line 1112) ... ok +test datafusion/core/src/lib.rs - user_guide_prepared_statements (line 1146) ... ok +test datafusion/core/src/lib.rs - user_guide_prepared_statements (line 1103) ... ok +test datafusion/core/src/lib.rs - user_guide_example_usage (line 1092) ... ok +test datafusion/core/src/lib.rs - user_guide_dataframe (line 1032) ... ok +test datafusion/core/src/lib.rs - user_guide_prepared_statements (line 1185) ... ok +test datafusion/core/src/dataframe/mod.rs - dataframe::DataFrame::describe (line 983) ... ok + +test result: ok. 184 passed; 0 failed; 45 ignored; 0 measured; 0 filtered out; finished in 0.47s + +all doctests ran in 7.57s; merged doctests compilation took 5.28s + Doc-tests datafusion_benchmarks + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_catalog + +running 1 test +test datafusion/catalog/src/table.rs - table::TableProvider::supports_filters_pushdown (line 234) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +all doctests ran in 1.62s; merged doctests compilation took 1.13s + Doc-tests datafusion_catalog_listing + +running 9 tests +test datafusion/catalog-listing/src/table.rs - table::ListingTable (line 138) - compile ... ok +test datafusion/catalog-listing/src/options.rs - options::ListingOptions::with_collect_stat (line 210) ... ok +test datafusion/catalog-listing/src/options.rs - options::ListingOptions::with_file_extension (line 98) ... ok +test datafusion/catalog-listing/src/options.rs - options::ListingOptions::with_target_partitions (line 227) ... ok +test datafusion/catalog-listing/src/options.rs - options::ListingOptions::with_table_partition_cols (line 179) ... ok +test datafusion/catalog-listing/src/config.rs - config::ListingTableConfig::with_listing_options (line 148) ... ok +test datafusion/catalog-listing/src/config.rs - config::ListingTableConfig::with_schema (line 108) ... ok +test datafusion/catalog-listing/src/options.rs - options::ListingOptions::with_file_extension_opt (line 118) ... ok +test datafusion/catalog-listing/src/options.rs - options::ListingOptions::with_file_sort_order (line 244) ... ok + +test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 2.31s; merged doctests compilation took 1.27s + Doc-tests datafusion_cli + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_common + +running 78 tests +test datafusion/common/src/config.rs - config::config_field (line 1720) ... ignored +test datafusion/common/src/config.rs - config::config_field (line 1728) ... ignored +test datafusion/common/src/config.rs - config::config_namespace (line 48) ... ignored +test datafusion/common/src/config.rs - config::config_namespace (line 66) ... ignored +test datafusion/common/src/datatype.rs - datatype::DataTypeExt::into_nullable_field (line 35) ... ok +test datafusion/common/src/datatype.rs - datatype::FieldExt::renamed (line 79) ... ok +test datafusion/common/src/datatype.rs - datatype::FieldExt::into_list_item (line 169) ... ok +test datafusion/common/src/datatype.rs - datatype::FieldExt::into_list (line 119) ... ok +test datafusion/common/src/config.rs - config::ConfigExtension (line 1542) ... ok +test datafusion/common/src/dfschema.rs - dfschema::DFSchema (line 98) ... ok +test datafusion/common/src/hash_utils.rs - hash_utils::with_hashes (line 78) ... ignored +test datafusion/common/src/dfschema.rs - dfschema::DFSchema (line 64) ... ok +test datafusion/common/src/datatype.rs - datatype::FieldExt::into_fixed_size_list (line 141) ... ok +test datafusion/common/src/dfschema.rs - dfschema::DFSchema::tree_string (line 890) ... ok +test datafusion/common/src/config.rs - config::extensions_options (line 1859) ... ok +test datafusion/common/src/datatype.rs - datatype::FieldExt::retyped (line 96) ... ok +test datafusion/common/src/error.rs - error::DataFusionErrorBuilder (line 699) ... ok +test datafusion/common/src/error.rs - error::DataFusionErrorBuilder::add_error (line 729) ... ok +test datafusion/common/src/diagnostic.rs - diagnostic::Diagnostic (line 30) ... ok +test datafusion/common/src/error.rs - error::DataFusionErrorBuilder (line 707) ... ok +test datafusion/common/src/dfschema.rs - dfschema::DFSchema (line 83) ... ok +test datafusion/common/src/metadata.rs - metadata::FieldMetadata (line 153) ... ok +test datafusion/common/src/error.rs - error::DataFusionErrorBuilder::with_error (line 745) ... ok +test datafusion/common/src/metadata.rs - metadata::FieldMetadata (line 166) ... ok +test datafusion/common/src/rounding.rs - rounding::next_down (line 202) ... ok +test datafusion/common/src/pruning.rs - pruning::PartitionPruningStatistics::try_new (line 189) ... ok +test datafusion/common/src/nested_struct.rs - nested_struct::cast_column (line 135) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue (line 220) ... ok +test datafusion/common/src/metadata.rs - metadata::FieldMetadata::merge_options (line 222) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue (line 237) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue (line 291) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue (line 262) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::convert_array_to_scalar_vec (line 3272) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue (line 277) ... ok +test datafusion/common/src/rounding.rs - rounding::next_up (line 167) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::convert_array_to_scalar_vec (line 3302) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::new_large_list (line 2839) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::new_list_from_iter (line 2795) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::convert_array_to_scalar_vec (line 3339) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::iter_to_array (line 2333) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::to_scalar (line 2306) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::try_as_str (line 3641) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::new_list (line 2734) ... ok +test datafusion/common/src/spans.rs - spans::Span::union_iter (line 122) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::try_new_null (line 1160) ... ok +test datafusion/common/src/scalar/struct_builder.rs - scalar::struct_builder::ScalarStructBuilder::new_null (line 59) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::ScalarValue::try_as_str (line 3655) ... ok +test datafusion/common/src/spans.rs - spans::Span::union (line 89) ... ok +test datafusion/common/src/scalar/struct_builder.rs - scalar::struct_builder::ScalarStructBuilder::new_null (line 47) ... ok +test datafusion/common/src/scalar/mod.rs - scalar::copy_array_data (line 4444) ... ok +test datafusion/common/src/stats.rs - stats::Statistics::try_merge (line 570) ... ok +test datafusion/common/src/table_reference.rs - table_reference::TableReference (line 55) ... ok +test datafusion/common/src/test_util.rs - test_util::arrow_test_data (line 228) ... ok +test datafusion/common/src/table_reference.rs - table_reference::TableReference::to_quoted_string (line 247) ... ok +test datafusion/common/src/test_util.rs - test_util::parquet_test_data (line 250) ... ok +test datafusion/common/src/tree_node.rs - tree_node::Transformed (line 619) ... ok +test datafusion/common/src/test_util.rs - test_util::datafusion_test_data (line 207) ... ok +test datafusion/common/src/tree_node.rs - tree_node::Transformed (line 602) ... ok +test datafusion/common/src/tree_node.rs - tree_node::Transformed (line 634) ... ok +test datafusion/common/src/types/logical.rs - types::logical::LogicalType (line 60) ... ok +test datafusion/common/src/tree_node.rs - tree_node::TransformedResult (line 1211) ... ok +test datafusion/common/src/utils/memory.rs - utils::memory::estimate_memory_size (line 49) ... ok +test datafusion/common/src/utils/memory.rs - utils::memory::estimate_memory_size (line 71) ... ok +test datafusion/common/src/types/native.rs - types::native::NativeType::Timestamp (line 129) ... ok +test datafusion/common/src/utils/mod.rs - utils::SingleRowListArrayBuilder (line 393) ... ok +test datafusion/common/src/test_util.rs - test_util::record_batch (line 368) ... ok +test datafusion/common/src/test_util.rs - test_util::assert_batches_eq (line 52) ... ok +test datafusion/common/src/utils/mod.rs - utils::coerced_type_with_base_type_only (line 581) ... ok +test datafusion/common/src/utils/mod.rs - utils::arrays_into_list_array (line 501) ... ok +test datafusion/common/src/utils/mod.rs - utils::base_type (line 550) ... ok +test datafusion/common/src/utils/mod.rs - utils::datafusion_strsim::levenshtein (line 756) ... ok +test datafusion/common/src/utils/mod.rs - utils::project_schema (line 49) ... ok +test datafusion/common/src/utils/mod.rs - utils::take_function_args (line 933) ... ok +test datafusion/common/src/utils/proxy.rs - utils::proxy::VecAllocExt::push_accounted (line 34) ... ok +test datafusion/common/src/utils/proxy.rs - utils::proxy::HashTableAllocExt::insert_accounted (line 128) ... ok +test datafusion/common/src/utils/proxy.rs - utils::proxy::VecAllocExt::allocated_size (line 73) ... ok +test datafusion/common/src/utils/mod.rs - utils::datafusion_strsim::normalized_levenshtein (line 778) ... ok +test datafusion/common/src/utils/proxy.rs - utils::proxy::VecAllocExt::push_accounted (line 54) ... ok + +test result: ok. 73 passed; 0 failed; 5 ignored; 0 measured; 0 filtered out; finished in 0.03s + +all doctests ran in 2.22s; merged doctests compilation took 1.45s + Doc-tests datafusion_common_runtime + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_datasource + +running 6 tests +test datafusion/datasource/src/write/mod.rs - write::ObjectWriterBuilder::with_buffer_size (line 181) ... ok +test datafusion/datasource/src/file_scan_config.rs - file_scan_config::FileScanConfigBuilder (line 193) ... ok +test datafusion/datasource/src/url.rs - url::ListingTableUrl::file_extension (line 211) ... ok +test datafusion/datasource/src/table_schema.rs - table_schema::TableSchema::new (line 100) ... ok +test datafusion/datasource/src/write/mod.rs - write::ObjectWriterBuilder::set_buffer_size (line 157) ... ok +test datafusion/datasource/src/file_scan_config.rs - file_scan_config::FileScanConfig (line 64) ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 2.16s; merged doctests compilation took 1.23s + Doc-tests datafusion_datasource_arrow + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_datasource_avro + +running 1 test +test datafusion/datasource-avro/src/avro_to_arrow/reader.rs - avro_to_arrow::reader::ReaderBuilder::new (line 58) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +all doctests ran in 1.71s; merged doctests compilation took 1.23s + Doc-tests datafusion_datasource_csv + +running 1 test +test datafusion/datasource-csv/src/source.rs - source::CsvSource (line 57) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 2.99s; merged doctests compilation took 2.05s + Doc-tests datafusion_datasource_json + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_datasource_parquet + +running 8 tests +test datafusion/datasource-parquet/src/row_filter.rs - row_filter::can_expr_be_pushed_down_with_schemas (line 474) ... ignored +test datafusion/datasource-parquet/src/row_filter.rs - row_filter::can_expr_be_pushed_down_with_schemas (line 491) ... ignored +test datafusion/datasource-parquet/src/row_filter.rs - row_filter::can_expr_be_pushed_down_with_schemas (line 507) ... ignored +test datafusion/datasource-parquet/src/supported_predicates.rs - supported_predicates::SupportsListPushdown (line 44) ... ignored +test datafusion/datasource-parquet/src/source.rs - source::ParquetSource (line 174) - compile ... ok +test datafusion/datasource-parquet/src/access_plan.rs - access_plan::ParquetAccessPlan (line 36) ... ok +test datafusion/datasource-parquet/src/source.rs - source::ParquetSource (line 92) ... ok +test datafusion/datasource-parquet/src/source.rs - source::ParquetSource (line 213) ... ok + +test result: ok. 4 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 2.28s; merged doctests compilation took 1.27s + Doc-tests datafusion_doc + +running 1 test +test datafusion/doc/src/lib.rs - DocumentationBuilder (line 197) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s + +all doctests ran in 2.33s; merged doctests compilation took 0.83s + Doc-tests datafusion_examples + +running 1 test +test datafusion-examples/src/utils/csv_to_parquet.rs - utils::csv_to_parquet::write_csv_to_parquet (line 57) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s + +all doctests ran in 12.76s; merged doctests compilation took 9.06s + Doc-tests datafusion_execution + +running 14 tests +test datafusion/execution/src/cache/lru_queue.rs - cache::lru_queue::LruQueue (line 31) ... ok +test datafusion/execution/src/config.rs - config::SessionConfig::options (line 142) ... ok +test datafusion/execution/src/config.rs - config::SessionConfig (line 46) ... ok +test datafusion/execution/src/object_store.rs - object_store::ObjectStoreUrl::parse (line 47) ... ok +test datafusion/execution/src/config.rs - config::SessionConfig (line 65) ... ok +test datafusion/execution/src/object_store.rs - object_store::ObjectStoreUrl::local_filesystem (line 77) ... ok +test datafusion/execution/src/config.rs - config::SessionConfig::options_mut (line 156) ... ok +test datafusion/execution/src/runtime_env.rs - runtime_env::RuntimeEnv (line 63) ... ok +test datafusion/execution/src/runtime_env.rs - runtime_env::RuntimeEnv (line 57) ... ok +test datafusion/execution/src/config.rs - config::SessionConfig::set_extension (line 563) ... ok +test datafusion/execution/src/config.rs - config::SessionConfig::with_extension (line 520) ... ok +test datafusion/execution/src/memory_pool/pool.rs - memory_pool::pool::TrackConsumersPool::new (line 353) ... ok +test datafusion/execution/src/runtime_env.rs - runtime_env::RuntimeEnv::register_object_store (line 164) ... ok +test datafusion/execution/src/runtime_env.rs - runtime_env::RuntimeEnv::register_object_store (line 152) ... ok + +test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + +all doctests ran in 4.94s; merged doctests compilation took 3.93s + Doc-tests datafusion_expr + +running 54 tests +test datafusion/expr/src/expr.rs - expr::Expr (line 242) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 178) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 144) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 194) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 265) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 163) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::alias_qualified_with_metadata (line 1717) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 227) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 292) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 132) ... ok +test datafusion/expr/src/expr.rs - expr::Expr (line 256) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::alias_with_metadata (line 1686) ... ok +test datafusion/expr/src/expr_fn.rs - expr_fn::ExprFunctionExt (line 741) - compile ... ok +test datafusion/expr/src/expr.rs - expr::Expr::schema_name (line 1483) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::column_refs (line 1939) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::sort (line 1837) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::try_as_col (line 1902) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::column_refs_counts (line 1973) ... ok +test datafusion/expr/src/expr_fn.rs - expr_fn::ident (line 97) ... ok +test datafusion/expr/src/expr_fn.rs - expr_fn::col (line 58) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::unalias (line 1741) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::unalias_nested (line 1768) ... ok +test datafusion/expr/src/expr.rs - expr::Expr::human_display (line 1511) ... ok +test datafusion/expr/src/expr_fn.rs - expr_fn::placeholder (line 120) ... ok +test datafusion/expr/src/expr_fn.rs - expr_fn::qualified_wildcard (line 154) ... ok +test datafusion/expr/src/expr_fn.rs - expr_fn::wildcard (line 136) ... ok +test datafusion/expr/src/logical_plan/builder.rs - logical_plan::builder::LogicalPlanBuilder::insert_into (line 441) ... ok +test datafusion/expr/src/expr_schema.rs - expr_schema::Expr::get_type (line 81) ... ok +test datafusion/expr/src/logical_plan/extension.rs - logical_plan::extension::UserDefinedLogicalNode::as_any (line 37) ... ok +test datafusion/expr/src/logical_plan/ddl.rs - logical_plan::ddl::CreateExternalTable::builder (line 250) ... ok +test datafusion/expr/src/logical_plan/builder.rs - logical_plan::builder::LogicalPlanBuilder::join_on (line 941) ... ok +test datafusion/expr/src/logical_plan/builder.rs - logical_plan::builder::LogicalPlanBuilder::scan (line 383) ... ok +test datafusion/expr/src/logical_plan/builder.rs - logical_plan::builder::LogicalPlanBuilder (line 93) ... ok +test datafusion/expr/src/logical_plan/plan.rs - logical_plan::plan::TableScanBuilder (line 2849) ... ignored +test datafusion/expr/src/logical_plan/extension.rs - logical_plan::extension::UserDefinedLogicalNode::dyn_eq (line 167) ... ok +test datafusion/expr/src/logical_plan/plan.rs - logical_plan::plan::LogicalPlan::display (line 1758) ... ok +test datafusion/expr/src/udf.rs - udf::ScalarUDF::call (line 145) - compile ... ok +test datafusion/expr/src/logical_plan/plan.rs - logical_plan::plan::LogicalPlan (line 158) ... ok +test datafusion/expr/src/logical_plan/plan.rs - logical_plan::plan::LogicalPlan::display_indent (line 1593) ... ok +test datafusion/expr/src/logical_plan/display.rs - logical_plan::display::display_schema (line 96) ... ok +test datafusion/expr/src/logical_plan/extension.rs - logical_plan::extension::UserDefinedLogicalNode::dyn_hash (line 130) ... ok +test datafusion/expr/src/logical_plan/plan.rs - logical_plan::plan::LogicalPlan (line 110) ... ok +test datafusion/expr/src/logical_plan/plan.rs - logical_plan::plan::LogicalPlan::display_graphviz (line 1700) ... ok +test datafusion/expr/src/logical_plan/plan.rs - logical_plan::plan::LogicalPlan::display_indent_schema (line 1635) ... ok +test datafusion/expr/src/udaf.rs - udaf::AggregateUDFImpl (line 366) ... ok +test datafusion/expr/src/logical_plan/plan.rs - logical_plan::plan::LogicalPlan::with_param_values (line 1238) ... ok +test datafusion/expr/src/select_expr.rs - select_expr::SelectExpr (line 38) ... ok +test datafusion/expr/src/udf.rs - udf::ScalarUDFImpl::return_field_from_args (line 616) ... ok +test datafusion/expr/src/udwf.rs - udwf::WindowUDFImpl (line 242) ... ok +test datafusion/expr/src/utils.rs - utils::split_binary_owned (line 1084) ... ok +test datafusion/expr/src/utils.rs - utils::split_conjunction_owned (line 1062) ... ok +test datafusion/expr/src/utils.rs - utils::disjunction (line 1176) ... ok +test datafusion/expr/src/utils.rs - utils::conjunction (line 1153) ... ok +test datafusion/expr/src/udf.rs - udf::ScalarUDFImpl (line 432) ... ok + +test result: ok. 53 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.30s + +all doctests ran in 3.39s; merged doctests compilation took 1.89s + Doc-tests datafusion_expr_common + +running 11 tests +test datafusion/expr-common/src/signature.rs - signature::Signature::with_parameter_names (line 1384) ... ok +test datafusion/expr-common/src/interval_arithmetic.rs - interval_arithmetic::NullableInterval (line 1694) ... ok +test datafusion/expr-common/src/interval_arithmetic.rs - interval_arithmetic::satisfy_greater (line 1318) ... ok +test datafusion/expr-common/src/signature.rs - signature::TypeSignature (line 131) ... ok +test datafusion/expr-common/src/signature.rs - signature::TypeSignature::arity (line 268) ... ok +test datafusion/expr-common/src/signature.rs - signature::Coercion (line 969) ... ok +test datafusion/expr-common/src/signature.rs - signature::TypeSignature (line 146) ... ok +test datafusion/expr-common/src/interval_arithmetic.rs - interval_arithmetic::NullableInterval::apply_operator (line 2007) ... ok +test datafusion/expr-common/src/interval_arithmetic.rs - interval_arithmetic::NullableInterval::single_value (line 2166) ... ok +test datafusion/expr-common/src/signature.rs - signature::ImplicitCoercion (line 1096) ... ok +test datafusion/expr-common/src/signature.rs - signature::TypeSignature::to_string_repr_with_names (line 611) ... ok + +test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 2.05s; merged doctests compilation took 1.38s + Doc-tests datafusion_ffi + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_functions + +running 7 tests +test datafusion/functions/src/datetime/mod.rs - datetime::expr_fn::to_char (line 152) ... ignored +test datafusion/functions/src/datetime/mod.rs - datetime::expr_fn::to_date (line 223) ... ignored +test datafusion/functions/src/regex/regexplike.rs - regex::regexplike::regexp_like (line 239) ... ignored +test datafusion/functions/src/regex/regexpreplace.rs - regex::regexpreplace::regexp_replace (line 212) ... ignored +test datafusion/functions/src/lib.rs - (line 49) ... ok +test datafusion/functions/src/lib.rs - (line 65) ... ok +test datafusion/functions/src/core/expr_ext.rs - core::expr_ext::FieldAccessor (line 39) ... ok + +test result: ok. 3 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.00s + +all doctests ran in 1.71s; merged doctests compilation took 1.08s + Doc-tests datafusion_functions_aggregate + +running 4 tests +test datafusion/functions-aggregate/src/min_max.rs - min_max::MovingMin (line 755) ... ok +test datafusion/functions-aggregate/src/count.rs - count::count_all (line 90) ... ok +test datafusion/functions-aggregate/src/min_max.rs - min_max::MovingMax (line 875) ... ok +test datafusion/functions-aggregate/src/count.rs - count::count_all_window (line 110) ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.67s + +all doctests ran in 5.98s; merged doctests compilation took 1.13s + Doc-tests datafusion_functions_aggregate_common + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_functions_nested + +running 2 tests +test datafusion/functions-nested/src/expr_ext.rs - expr_ext::IndexAccessor (line 36) ... ok +test datafusion/functions-nested/src/expr_ext.rs - expr_ext::SliceAccessor (line 65) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +all doctests ran in 2.10s; merged doctests compilation took 1.89s + Doc-tests datafusion_functions_table + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_functions_window + +running 7 tests +test datafusion/functions-window/src/macros.rs - macros::get_or_init_udwf (line 41) ... ok +test datafusion/functions-window/src/macros.rs - macros::create_udwf_expr (line 140) ... ok +test datafusion/functions-window/src/macros.rs - macros::define_udwf_and_expr (line 356) ... ok +test datafusion/functions-window/src/macros.rs - macros::define_udwf_and_expr (line 420) ... ok +test datafusion/functions-window/src/macros.rs - macros::define_udwf_and_expr (line 574) ... ok +test datafusion/functions-window/src/macros.rs - macros::create_udwf_expr (line 208) ... ok +test datafusion/functions-window/src/macros.rs - macros::define_udwf_and_expr (line 485) ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 1.38s; merged doctests compilation took 1.22s + Doc-tests datafusion_functions_window_common + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_macros + +running 2 tests +test datafusion/macros/src/user_doc.rs - user_doc (line 37) ... ignored +test datafusion/macros/src/user_doc.rs - user_doc (line 64) ... ignored + +test result: ok. 0 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 0.00s + +all doctests ran in 0.95s; merged doctests compilation took 0.83s + Doc-tests datafusion_optimizer + +running 6 tests +test datafusion/optimizer/src/simplify_expressions/simplify_literal.rs - simplify_expressions::simplify_literal::parse_literal (line 41) ... ignored +test datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs - simplify_expressions::expr_simplifier::ExprSimplifier::with_canonicalize (line 330) ... ok +test datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs - simplify_expressions::expr_simplifier::ExprSimplifier::with_max_cycles (line 388) ... ok +test datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs - simplify_expressions::expr_simplifier::ExprSimplifier::simplify (line 145) ... ok +test datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs - simplify_expressions::expr_simplifier::ExprSimplifier (line 76) ... ok +test datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs - simplify_expressions::expr_simplifier::ExprSimplifier::with_guarantees (line 270) ... ok + +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 1.75s; merged doctests compilation took 1.30s + Doc-tests datafusion_physical_expr + +running 12 tests +test datafusion/physical-expr/src/equivalence/class.rs - equivalence::class::ConstExpr (line 80) ... ok +test datafusion/physical-expr/src/projection.rs - projection::ProjectionExprs::try_merge (line 303) ... ok +test datafusion/physical-expr/src/projection.rs - projection::ProjectionExprs::try_map_exprs (line 262) ... ok +test datafusion/physical-expr/src/projection.rs - projection::ProjectionExprs::from_indices (line 192) ... ok +test datafusion/physical-expr/src/expressions/column.rs - expressions::column::Column (line 47) ... ok +test datafusion/physical-expr/src/aggregate.rs - aggregate::AggregateExprBuilder::build (line 106) ... ok +test datafusion/physical-expr/src/projection.rs - projection::ProjectionExprs::project_statistics (line 517) ... ok +test datafusion/physical-expr/src/equivalence/properties/mod.rs - equivalence::properties::EquivalenceProperties (line 107) ... ok +test datafusion/physical-expr/src/intervals/cp_solver.rs - intervals::cp_solver::ExprIntervalGraph::evaluate_bounds (line 560) ... ok +test datafusion/physical-expr/src/planner.rs - planner::create_physical_expr (line 72) ... ok +test datafusion/physical-expr/src/physical_expr.rs - physical_expr::create_ordering (line 107) ... ok +test datafusion/physical-expr/src/planner.rs - planner::create_physical_expr (line 54) ... ok + +test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 1.84s; merged doctests compilation took 1.38s + Doc-tests datafusion_physical_expr_adapter + +running 3 tests +test datafusion/physical-expr-adapter/src/schema_rewriter.rs - schema_rewriter::DefaultPhysicalExprAdapter (line 224) ... ok +test datafusion/physical-expr-adapter/src/schema_rewriter.rs - schema_rewriter::PhysicalExprAdapter (line 104) ... ok +test datafusion/physical-expr-adapter/src/schema_rewriter.rs - schema_rewriter::BatchAdapterFactory (line 493) ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 1.64s; merged doctests compilation took 1.26s + Doc-tests datafusion_physical_expr_common + +running 8 tests +test datafusion/physical-expr-common/src/sort_expr.rs - sort_expr::PhysicalSortExpr (line 38) ... ok +test datafusion/physical-expr-common/src/sort_expr.rs - sort_expr::is_reversed_sort_options (line 478) ... ok +test datafusion/physical-expr-common/src/metrics/builder.rs - metrics::builder::MetricBuilder (line 36) ... ok +test datafusion/physical-expr-common/src/physical_expr.rs - physical_expr::fmt_sql (line 518) ... ok +test datafusion/physical-expr-common/src/metrics/custom.rs - metrics::custom::CustomMetricValue (line 41) ... ok +test datafusion/physical-expr-common/src/metrics/baseline.rs - metrics::baseline::BaselineMetrics (line 31) ... ok +test datafusion/physical-expr-common/src/metrics/value.rs - metrics::value::MetricValue::ElapsedCompute (line 605) ... ok +test datafusion/physical-expr-common/src/metrics/mod.rs - metrics::Metric (line 51) ... ok + +test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 1.50s; merged doctests compilation took 1.22s + Doc-tests datafusion_physical_optimizer + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_physical_plan + +running 14 tests +test datafusion/physical-plan/src/unnest.rs - unnest::create_take_indices (line 915) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::create_take_indices (line 920) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::repeat_arrs_from_indices (line 978) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::unnest_list_array (line 866) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::unnest_list_array (line 873) ... ignored +test datafusion/physical-plan/src/execution_plan.rs - execution_plan::ExecutionPlan::execute (line 381) ... ok +test datafusion/physical-plan/src/execution_plan.rs - execution_plan::ExecutionPlan::execute (line 419) ... ok +test datafusion/physical-plan/src/execution_plan.rs - execution_plan::ExecutionPlan::execute (line 348) ... ok +test datafusion/physical-plan/src/sort_pushdown.rs - sort_pushdown::SortOrderPushdownResult::into_inexact (line 99) ... ok +test datafusion/physical-plan/src/stream.rs - stream::RecordBatchStreamAdapter::new (line 420) ... ok +test datafusion/physical-plan/src/stream.rs - stream::RecordBatchReceiverStreamBuilder (line 194) ... ok +test datafusion/physical-plan/src/projection.rs - projection::ProjectionExec::try_new (line 90) ... ok +test datafusion/physical-plan/src/display.rs - display::DisplayableExecutionPlan (line 86) ... ok +test datafusion/physical-plan/src/spill/spill_pool.rs - spill::spill_pool::channel (line 364) ... ok + +test result: ok. 9 passed; 0 failed; 5 ignored; 0 measured; 0 filtered out; finished in 0.01s + + +running 10 tests +test datafusion/physical-plan/src/unnest.rs - unnest::build_batch (line 587) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::find_longest_length (line 739) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::find_longest_length (line 746) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::find_longest_length (line 753) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::repeat_arrs_from_indices (line 949) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::repeat_arrs_from_indices (line 957) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::repeat_arrs_from_indices (line 964) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::repeat_arrs_from_indices (line 970) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::repeat_arrs_from_indices (line 984) ... ignored +test datafusion/physical-plan/src/unnest.rs - unnest::unnest_list_array (line 860) ... ignored + +test result: ok. 0 passed; 0 failed; 10 ignored; 0 measured; 0 filtered out; finished in 0.00s + +all doctests ran in 2.01s; merged doctests compilation took 1.56s + Doc-tests datafusion_proto + +running 4 tests +test datafusion/proto/src/lib.rs - (line 63) ... ok +test datafusion/proto/src/lib.rs - (line 82) ... ok +test datafusion/proto/src/bytes/mod.rs - bytes::Serializeable (line 50) ... ok +test datafusion/proto/src/lib.rs - (line 104) ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s + +all doctests ran in 4.24s; merged doctests compilation took 1.94s + Doc-tests datafusion_proto_common + +running 1 test +test datafusion/proto-common/src/lib.rs - (line 59) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +all doctests ran in 1.44s; merged doctests compilation took 1.30s + Doc-tests datafusion_pruning + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_session + +running 1 test +test datafusion/session/src/session.rs - session::Session (line 53) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +all doctests ran in 1.18s; merged doctests compilation took 1.06s + Doc-tests datafusion_spark + +running 4 tests +test datafusion/spark/src/lib.rs - (line 100) ... ignored +test datafusion/spark/src/lib.rs - (line 44) ... ok +test datafusion/spark/src/lib.rs - (line 87) ... ok +test datafusion/spark/src/session_state.rs - session_state::SessionStateBuilderSpark (line 36) ... ok + +test result: ok. 3 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 2.85s; merged doctests compilation took 1.53s + Doc-tests datafusion_sql + +running 13 tests +test datafusion/sql/src/unparser/ast.rs - unparser::ast::SelectBuilder::already_projected (line 196) ... ignored +test datafusion/sql/src/parser.rs - parser::DFParserBuilder (line 350) ... ok +test datafusion/sql/src/planner.rs - planner::ParserOptions::with_parse_float_as_decimal (line 91) ... ok +test datafusion/sql/src/planner.rs - planner::ParserOptions::new (line 67) ... ok +test datafusion/sql/src/unparser/dialect.rs - unparser::dialect::CustomDialectBuilder (line 804) ... ok +test datafusion/sql/src/planner.rs - planner::ParserOptions::with_enable_ident_normalization (line 105) ... ok +test datafusion/sql/src/resolve.rs - resolve::resolve_table_references (line 203) ... ok +test datafusion/sql/src/resolve.rs - resolve::resolve_table_references (line 217) ... ok +test datafusion/sql/src/unparser/mod.rs - unparser::Unparser<'a>::with_pretty (line 98) ... ok +test datafusion/sql/src/unparser/expr.rs - unparser::expr::expr_to_sql (line 69) ... ok +test datafusion/sql/src/parser.rs - parser::DFParserBuilder (line 337) ... ok +test datafusion/sql/src/unparser/mod.rs - unparser::Unparser (line 42) ... ok +test datafusion/sql/src/unparser/plan.rs - unparser::plan::plan_to_sql (line 69) ... ok + +test result: ok. 12 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s + +all doctests ran in 1.71s; merged doctests compilation took 1.25s + Doc-tests datafusion_sqllogictest + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests datafusion_substrait + +running 3 tests +test datafusion/substrait/src/logical_plan/consumer/substrait_consumer.rs - logical_plan::consumer::substrait_consumer::SubstraitConsumer (line 56) ... ok +test datafusion/substrait/src/logical_plan/producer/substrait_producer.rs - logical_plan::producer::substrait_producer::SubstraitProducer (line 54) ... ok +test datafusion/substrait/src/lib.rs - (line 61) ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + +all doctests ran in 4.98s; merged doctests compilation took 3.56s + Doc-tests datafusion_wasmtest + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests ffi_example_table_provider + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests ffi_module_interface + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests test_utils + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + diff --git a/q.sql b/q.sql new file mode 100644 index 0000000000000..6377e81a3efda --- /dev/null +++ b/q.sql @@ -0,0 +1,12 @@ +copy ( + select {f1: 1, f2: 2} as s +) to 'struct.parquet'; + +create external table struct +stored as parquet +location 'struct.parquet'; + +SELECT + get_field(s, 'f1') AS __datafusion_extracted_2 +FROM struct +WHERE COALESCE(get_field(s, 'f1'), get_field(s, 'f2')) = 42; \ No newline at end of file diff --git a/split-pr-filters.md b/split-pr-filters.md new file mode 100644 index 0000000000000..d9d08b6bd1aa1 --- /dev/null +++ b/split-pr-filters.md @@ -0,0 +1,531 @@ +# PR B: Consolidate Filter Classification into Physical Planner + +## Context + +This is part of splitting PR #20061 "Consolidate filters and projections onto TableScan" into two smaller PRs. This is the **second PR** that builds on PR A (projection-expressions). + +**Prerequisite:** PR A (projection-expressions) must be merged first +**Target branch to create:** `filter-consolidation` (from `projection-expressions`) + +## Goal + +Move ALL filter expressions to `TableScan.filters` during logical optimization, deferring the classification (Exact/Inexact/Unsupported) to the physical planner. + +**Current behavior (after PR A):** +- Optimizer calls `supports_filters_pushdown()` to classify filters +- Exact/Inexact filters go to `TableScan.filters` +- Unsupported filters stay as `Filter` nodes above the scan +- Physical planner just passes filters to source + +**Target behavior (after this PR):** +- Optimizer moves ALL filters to `TableScan.filters` (no classification) +- Physical planner calls `supports_filters_pushdown()` to classify +- Physical planner creates `FilterExec` for post-scan filters + +--- + +## Why This Change + +1. **Cleaner separation**: Logical plan doesn't need to know provider capabilities +2. **Better physical planning**: Physical planner has access to session state for smarter decisions +3. **Simpler optimizer**: No need to query TableSource during optimization + +--- + +## Files to Modify + +### 1. `datafusion/optimizer/src/push_down_filter.rs` + +**Major changes - simplify filter handling:** + +Find the `LogicalPlan::TableScan(scan)` case (around line 1124-1170). + +**Current code (after PR A):** +```rust +LogicalPlan::TableScan(scan) => { + let filter_predicates = split_conjunction(&filter.predicate); + + let (volatile_filters, non_volatile_filters): (Vec<&Expr>, Vec<&Expr>) = + filter_predicates.into_iter().partition(|pred| pred.is_volatile()); + + // Check which non-volatile filters are supported by source + let supported_filters = scan.source + .supports_filters_pushdown(non_volatile_filters.as_slice())?; + + // Compose scan filters from supported ones + let zip = non_volatile_filters.into_iter().zip(supported_filters); + let new_scan_filters = zip.clone() + .filter(|(_, res)| res != &TableProviderFilterPushDown::Unsupported) + .map(|(pred, _)| pred); + + // Add new scan filters + let new_scan_filters: Vec = scan.filters.iter() + .chain(new_scan_filters) + .unique() + .cloned() + .collect(); + + // Create Filter node for unsupported/inexact filters + let new_predicate: Vec = zip + .filter(|(_, res)| res != &TableProviderFilterPushDown::Exact) + .map(|(pred, _)| pred) + .chain(volatile_filters) + .cloned() + .collect(); + + let new_scan = LogicalPlan::TableScan(TableScan { + filters: new_scan_filters, + ..scan + }); + + Transformed::yes(new_scan).transform_data(|new_scan| { + if let Some(predicate) = conjunction(new_predicate) { + make_filter(predicate, Arc::new(new_scan)).map(Transformed::yes) + } else { + Ok(Transformed::no(new_scan)) + } + }) +} +``` + +**New code (simplified):** +```rust +LogicalPlan::TableScan(scan) => { + // Move ALL filters to the TableScan. + // Exclude scalar subqueries - they are essentially a fork in the logical + // plan tree that should not be processed by TableScan nodes. + let filter_predicates = split_conjunction(&filter.predicate); + + // Partition predicates: scalar subqueries must stay in a Filter node + let (scalar_subquery_filters, pushable_filters): (Vec<_>, Vec<_>) = + filter_predicates.iter().partition(|pred| { + pred.exists(|e| Ok(matches!(e, Expr::ScalarSubquery(_)))).unwrap() + }); + + // Combine existing scan filters with pushable filter predicates + let new_scan_filters: Vec = scan.filters.iter() + .chain(pushable_filters) + .unique() + .cloned() + .collect(); + + let new_scan = LogicalPlan::TableScan(TableScan { + filters: new_scan_filters, + ..scan + }); + + // Keep scalar subquery filters in a Filter node above the TableScan + let remaining_predicates: Vec = + scalar_subquery_filters.into_iter().cloned().collect(); + + if let Some(predicate) = conjunction(remaining_predicates) { + make_filter(predicate, Arc::new(new_scan)).map(Transformed::yes) + } else { + Ok(Transformed::yes(new_scan)) + } +} +``` + +**Key changes:** +1. Remove `supports_filters_pushdown()` call +2. Remove filter classification logic +3. Move ALL filters (except scalar subqueries) to `TableScan.filters` +4. Only keep `Filter` nodes for scalar subquery predicates + +**Also remove unused imports:** +```rust +// Remove these if no longer used: +use datafusion_expr::TableProviderFilterPushDown; +// Remove assert_eq_or_internal_err if only used for filter count check +``` + +### 2. `datafusion/core/src/physical_planner.rs` + +**Major changes - add filter classification:** + +Update `plan_table_scan()` to classify filters and create `FilterExec`: + +```rust +async fn plan_table_scan( + &self, + scan: &TableScan, + session_state: &SessionState, +) -> Result> { + use datafusion_expr::TableProviderFilterPushDown; + + let provider = source_as_provider(&scan.source)?; + let source_schema = scan.source.schema(); + + // Remove all qualifiers from filters as the provider doesn't know + // (nor should care) how the relation was referred to in the query + let filters: Vec = unnormalize_cols(scan.filters.iter().cloned()); + + // Separate volatile filters (they should never be pushed down) + let (volatile_filters, non_volatile_filters): (Vec, Vec) = filters + .into_iter() + .partition(|pred: &Expr| pred.is_volatile()); + + // Classify filters using supports_filters_pushdown + let filter_refs: Vec<&Expr> = non_volatile_filters.iter().collect(); + let supported = provider.supports_filters_pushdown(&filter_refs)?; + + assert_eq!( + non_volatile_filters.len(), + supported.len(), + "supports_filters_pushdown returned {} results for {} filters", + supported.len(), + non_volatile_filters.len() + ); + + // Separate filters into: + // - pushable_filters: Exact or Inexact filters to pass to the provider + // - post_scan_filters: Inexact, Unsupported, and volatile filters for FilterExec + let mut pushable_filters = Vec::new(); + let mut post_scan_filters = Vec::new(); + + for (filter, support) in non_volatile_filters.into_iter().zip(supported.iter()) { + match support { + TableProviderFilterPushDown::Exact => { + pushable_filters.push(filter); + } + TableProviderFilterPushDown::Inexact => { + pushable_filters.push(filter.clone()); + post_scan_filters.push(filter); + } + TableProviderFilterPushDown::Unsupported => { + post_scan_filters.push(filter); + } + } + } + + // Add volatile filters to post_scan_filters + post_scan_filters.extend(volatile_filters); + + // Compute required column indices for the scan + // We need columns from BOTH projection expressions AND post-scan filters + let scan_projection = self.compute_scan_projection( + &scan.projection, + &post_scan_filters, + &source_schema, + )?; + + // Check if we have inexact filters - if so, we can't push limit + let has_inexact = supported.contains(&TableProviderFilterPushDown::Inexact); + let scan_limit = if has_inexact || !post_scan_filters.is_empty() { + None // Can't push limit when post-filtering is needed + } else { + scan.fetch + }; + + // Create the scan + let scan_args = ScanArgs::default() + .with_projection(scan_projection.as_deref()) + .with_filters(if pushable_filters.is_empty() { + None + } else { + Some(&pushable_filters) + }) + .with_limit(scan_limit); + + let scan_result = provider.scan_with_args(session_state, scan_args).await?; + let mut plan: Arc = Arc::clone(scan_result.plan()); + + // Create a DFSchema from the scan output for filter and projection creation + let scan_output_schema = plan.schema(); + let scan_df_schema = DFSchema::try_from(scan_output_schema.as_ref().clone())?; + + // Wrap with FilterExec if needed + if !post_scan_filters.is_empty() { + if let Some(filter_expr) = conjunction(post_scan_filters) { + let num_scan_columns = scan_output_schema.fields().len(); + plan = self.create_filter_exec( + &filter_expr, + plan, + &scan_df_schema, + session_state, + num_scan_columns, + )?; + } + } + + // Wrap with ProjectionExec if projection is present and differs from scan output + if let Some(ref proj_exprs) = scan.projection { + let needs_projection = !self.is_identity_column_projection(proj_exprs, &source_schema) + || scan_output_schema.fields().len() != proj_exprs.len(); + + if needs_projection { + let unnormalized_proj_exprs = unnormalize_cols(proj_exprs.iter().cloned()); + plan = self.create_projection_exec( + &unnormalized_proj_exprs, + plan, + &scan_df_schema, + session_state, + )?; + } + } + + // Apply limit if it wasn't pushed to scan + if let Some(fetch) = scan.fetch { + if scan_limit.is_none() { + plan = Arc::new(GlobalLimitExec::new(plan, 0, Some(fetch))); + } + } + + Ok(plan) +} +``` + +**Add compute_scan_projection helper:** +```rust +/// Compute the column indices needed for the scan based on projection +/// expressions and post-scan filters. +fn compute_scan_projection( + &self, + projection: &Option>, + post_filters: &[Expr], + source_schema: &Schema, +) -> Result>> { + use std::collections::HashSet; + + // Collect all columns needed + let mut required_columns = HashSet::new(); + + // Add columns from projection expressions + if let Some(exprs) = projection { + for expr in exprs { + expr.apply(|e| { + if let Expr::Column(col) = e { + required_columns.insert(col.name().to_string()); + } + Ok(TreeNodeRecursion::Continue) + })?; + } + } + + // Add columns from post-scan filters + for filter in post_filters { + filter.apply(|e| { + if let Expr::Column(col) = e { + required_columns.insert(col.name().to_string()); + } + Ok(TreeNodeRecursion::Continue) + })?; + } + + // If no projection specified and no filters, return None (all columns) + if projection.is_none() && post_filters.is_empty() { + return Ok(None); + } + + // If projection is None but we have filters, we need all columns + if projection.is_none() { + return Ok(None); + } + + // Convert column names to indices + let indices: Vec = required_columns + .iter() + .filter_map(|name| source_schema.index_of(name).ok()) + .sorted() + .collect(); + + if indices.is_empty() { + Ok(None) + } else { + Ok(Some(indices)) + } +} +``` + +**Add create_filter_exec helper** (handles async UDFs): +```rust +fn create_filter_exec( + &self, + predicate: &Expr, + input: Arc, + input_dfschema: &DFSchema, + session_state: &SessionState, + num_input_columns: usize, +) -> Result> { + let runtime_expr = self.create_physical_expr(predicate, input_dfschema, session_state)?; + let input_schema = input.schema(); + + let filter = match self.try_plan_async_exprs( + num_input_columns, + PlannedExprResult::Expr(vec![runtime_expr]), + input_schema.as_ref(), + )? { + PlanAsyncExpr::Sync(PlannedExprResult::Expr(runtime_expr)) => { + FilterExecBuilder::new(Arc::clone(&runtime_expr[0]), input) + .with_batch_size(session_state.config().batch_size()) + .build()? + } + PlanAsyncExpr::Async(async_map, PlannedExprResult::Expr(runtime_expr)) => { + let async_exec = AsyncFuncExec::try_new(async_map.async_exprs, input)?; + FilterExecBuilder::new(Arc::clone(&runtime_expr[0]), Arc::new(async_exec)) + .apply_projection(Some((0..num_input_columns).collect()))? + .with_batch_size(session_state.config().batch_size()) + .build()? + } + _ => return internal_err!("Unexpected result from try_plan_async_exprs"), + }; + + let selectivity = session_state + .config() + .options() + .optimizer + .default_filter_selectivity; + + Ok(Arc::new(filter.with_default_selectivity(selectivity)?)) +} +``` + +**Also update extract_dml_filters** to include TableScan filters: +```rust +fn extract_dml_filters(input: &Arc) -> Result> { + let mut filters = Vec::new(); + + input.apply(|node| { + match node { + LogicalPlan::Filter(filter) => { + filters.extend(split_conjunction(&filter.predicate).into_iter().cloned()); + } + LogicalPlan::TableScan(scan) => { + // Also extract filters from TableScan (where they may be pushed down) + filters.extend(scan.filters.iter().cloned()); + } + _ => {} + } + Ok(TreeNodeRecursion::Continue) + })?; + + Ok(filters) +} +``` + +### 3. Update imports in physical_planner.rs + +Add: +```rust +use std::collections::HashSet; +use datafusion_expr::TableProviderFilterPushDown; +use datafusion_expr::utils::conjunction; +``` + +### 4. Test Files (`.slt` files) + +Update expected plans to show: +- Filters on TableScan instead of separate Filter nodes +- No separate `Filter:` nodes for pushable filters + +**Example change:** +``` +# Before (after PR A): +physical_plan +01)ProjectionExec: ... +02)--FilterExec: a > 10 +03)----DataSourceExec: ... + +# After (this PR): +physical_plan +01)ProjectionExec: ... +02)--DataSourceExec: ..., filters=[a > 10] +``` + +For Unsupported/Inexact filters, `FilterExec` will still appear but created by physical planner. + +--- + +## Edge Cases to Handle + +### 1. Scalar Subqueries +Scalar subquery expressions must stay as `Filter` nodes (handled in push_down_filter). + +### 2. Volatile Expressions +Functions like `random()` should never be pushed to the source. They go to `FilterExec`. + +### 3. Async UDFs +The `create_filter_exec` helper handles async UDFs by wrapping with `AsyncFuncExec`. + +### 4. Limit Pushdown +If there are post-scan filters (Inexact/Unsupported), limit cannot be pushed to scan. + +--- + +## Implementation Steps + +1. Create branch from projection-expressions: + ```bash + git checkout projection-expressions + git pull origin projection-expressions + git checkout -b filter-consolidation + ``` + +2. Simplify push_down_filter.rs (remove classification) + +3. Enhance physical_planner.rs with filter classification + +4. Add compute_scan_projection and create_filter_exec helpers + +5. Update extract_dml_filters + +6. Update test expected outputs + +7. Run tests: + ```bash + cargo test -p datafusion-optimizer + cargo test -p datafusion-core + cargo test -p datafusion-sqllogictest + ``` + +8. Create PR: + ```bash + git add -A + git commit -m "Consolidate filter classification into physical planner" + git push -u origin filter-consolidation + ``` + +--- + +## PR Description + +```markdown +## Summary +Moves all filter expressions to `TableScan.filters` during logical optimization, +deferring the classification (Exact/Inexact/Unsupported) to the physical planner. + +## Related Issues +Closes #19894. Helps with #19387. + +## Changes +- Simplified `push_down_filter` to move all filters to TableScan +- Physical planner now calls `supports_filters_pushdown` and creates `FilterExec` +- Updated `compute_scan_projection` to include columns needed by post-scan filters +- Handles async UDFs in filters via `create_filter_exec` helper + +## Why This Change +- Cleaner separation: logical plan doesn't need to know provider capabilities +- Enables better physical planning decisions at execution time +- Physical planner has access to session state for smarter decisions + +## Test Plan +- All existing tests pass with updated expected outputs +- Verified filter pushdown works correctly with Exact/Inexact/Unsupported filters +``` + +--- + +## Key Differences from Original PR #20061 + +1. **Builds on PR A** - assumes projection expressions are already done +2. **Focused scope** - only filter consolidation changes +3. **Smaller diff** - no projection-related changes + +## Reference: Original PR #20061 Commits + +The original PR has these commits: +- `0166985f9 Consolidate filters and projections onto TableScan` - main commit +- `e61159874 handle async udfs` - async UDF fix +- `fc6807c8c fix tests by blocking on subquery expressions` - subquery fix + +The async UDF handling and scalar subquery blocking are included in this plan. diff --git a/split-pr-projection.md b/split-pr-projection.md new file mode 100644 index 0000000000000..c60320b2daf61 --- /dev/null +++ b/split-pr-projection.md @@ -0,0 +1,374 @@ +# PR A: Change TableScan.projection to Use Expressions + +## Context + +This is part of splitting PR #20061 "Consolidate filters and projections onto TableScan" into two smaller PRs. This is the **first PR** that must be completed before PR B (filter consolidation). + +**Current branch:** `move-filters` contains the combined changes +**Target branch to create:** `projection-expressions` (from `main`) + +## Goal + +Change `TableScan.projection` from `Option>` (column indices) to `Option>` (expressions), enabling projection expressions to be represented directly on table scans. + +**Important:** This PR should NOT include filter consolidation changes. Filter pushdown must continue to work as it does today (optimizer classifies filters, creates `Filter` nodes for unsupported filters). + +--- + +## Current State (main branch) + +### TableScan struct (`datafusion/expr/src/logical_plan/plan.rs`) +```rust +pub struct TableScan { + pub table_name: TableReference, + pub source: Arc, + pub projection: Option>, // Column INDICES + pub projected_schema: DFSchemaRef, + pub filters: Vec, + pub fetch: Option, +} +``` + +### How projections work today +1. SQL parser creates `TableScan` with column indices +2. `optimize_projections` optimizer rule works with indices +3. Physical planner receives indices and passes them directly to `scan_with_args()` +4. No `ProjectionExec` is created for table scans (projection is pushed to source) + +### How filters work today (KEEP THIS BEHAVIOR) +1. `push_down_filter` optimizer calls `supports_filters_pushdown()` on the source +2. Filters are classified as Exact/Inexact/Unsupported +3. Exact/Inexact filters go to `TableScan.filters` +4. Unsupported filters stay as `Filter` nodes above the scan +5. Physical planner just passes filters to source, doesn't create `FilterExec` + +--- + +## Target State (after this PR) + +### TableScan struct +```rust +pub struct TableScan { + pub table_name: TableReference, + pub source: Arc, + pub projection: Option>, // Column EXPRESSIONS + pub projected_schema: DFSchemaRef, + pub filters: Vec, // No change to filter handling + pub fetch: Option, +} +``` + +### New TableScanBuilder +```rust +pub struct TableScanBuilder { + table_name: TableReference, + table_source: Arc, + projection: Option>, + filters: Vec, + fetch: Option, +} +``` + +--- + +## Files to Modify + +### 1. `datafusion/expr/src/logical_plan/plan.rs` + +**Changes needed:** + +1. **Change TableScan.projection type** (around line 2688): + ```rust + // FROM: + pub projection: Option>, + + // TO: + pub projection: Option>, + ``` + +2. **Update TableScan::try_new()** for backward compatibility - convert indices to column expressions: + ```rust + pub fn try_new( + table_name: impl Into, + table_source: Arc, + projection: Option>, // Keep this signature for compat + filters: Vec, + fetch: Option, + ) -> Result { + // ... validation ... + let schema = table_source.schema(); + + // Convert indices to column expressions + let projection_exprs = projection.as_ref().map(|indices| { + indices.iter().map(|&i| { + let field = schema.field(i); + Expr::Column(Column::new_unqualified(field.name())) + }).collect::>() + }); + + // Build projected_schema from expressions... + } + ``` + +3. **Add TableScanBuilder** (new struct): + ```rust + pub struct TableScanBuilder { + table_name: TableReference, + table_source: Arc, + projection: Option>, + filters: Vec, + fetch: Option, + } + + impl TableScanBuilder { + pub fn new(table_name: impl Into, table_source: Arc) -> Self { ... } + pub fn with_projection(mut self, projection: Option>) -> Self { ... } + pub fn with_filters(mut self, filters: Vec) -> Self { ... } + pub fn with_fetch(mut self, fetch: Option) -> Self { ... } + pub fn build(self) -> Result { ... } + } + ``` + +4. **Update Display impl** to show expression names instead of indices: + ```rust + // In the display code for TableScan + let names: Vec = exprs.iter().map(|e| { + if let Expr::Column(col) = e { + col.name.clone() + } else { + e.schema_name().to_string() + } + }).collect(); + ``` + +5. **Update Hash and PartialOrd impls** to handle `Vec` instead of `Vec` + +6. **Add helper function** in `datafusion/expr/src/utils.rs`: + ```rust + /// Extract column indices from projection expressions that are simple column references + pub fn projection_indices_from_exprs(exprs: &[Expr], schema: &Schema) -> Option> { + exprs.iter().map(|e| { + if let Expr::Column(col) = e { + schema.index_of(col.name()).ok() + } else { + None + } + }).collect() + } + ``` + +### 2. `datafusion/optimizer/src/optimize_projections/mod.rs` + +**Changes needed:** + +The optimizer rule works with required column indices. Update it to convert indices to expressions when updating TableScan. + +Find the TableScan handling (around line 255-299): +```rust +// Current code works with indices +let projection = match &projection { + Some(projection) => indices.into_mapped_indices(|idx| projection[idx]), + None => indices.into_inner(), +}; + +// Change to work with expressions +let new_projection = match &projection { + Some(proj_exprs) => { + let new_exprs: Vec = required_indices + .iter() + .filter_map(|&idx| proj_exprs.get(idx).cloned()) + .collect(); + Some(new_exprs) + } + None => { + let new_exprs: Vec = required_indices + .iter() + .map(|&idx| { + let field = source_schema.field(idx); + Expr::Column(Column::new_unqualified(field.name())) + }) + .collect(); + Some(new_exprs) + } +}; +``` + +### 3. `datafusion/optimizer/src/optimize_projections/required_indices.rs` + +Remove or update any index-based helpers that are no longer needed. + +### 4. `datafusion/core/src/physical_planner.rs` + +**Changes needed:** + +Create a new `plan_table_scan()` method that handles projection expressions. + +```rust +async fn plan_table_scan( + &self, + scan: &TableScan, + session_state: &SessionState, +) -> Result> { + let provider = source_as_provider(&scan.source)?; + let source_schema = scan.source.schema(); + + // Convert projection expressions to indices for the source + // (sources still expect indices) + let projection_indices = scan.projection.as_ref().and_then(|exprs| { + projection_indices_from_exprs(exprs, &source_schema) + }); + + // Unnormalize filters (existing behavior) + let filters = unnormalize_cols(scan.filters.iter().cloned()); + let filters_vec: Vec = filters.into_iter().collect(); + + // Create scan with indices + let scan_args = ScanArgs::default() + .with_projection(projection_indices.as_deref()) + .with_filters(if filters_vec.is_empty() { None } else { Some(&filters_vec) }) + .with_limit(scan.fetch); + + let scan_result = provider.scan_with_args(session_state, scan_args).await?; + let mut plan: Arc = Arc::clone(scan_result.plan()); + + // If projection has non-column expressions, wrap with ProjectionExec + if let Some(ref proj_exprs) = scan.projection { + if !self.is_identity_column_projection(proj_exprs, &source_schema) { + plan = self.create_projection_exec(proj_exprs, plan, session_state)?; + } + } + + Ok(plan) +} + +fn is_identity_column_projection(&self, exprs: &[Expr], schema: &Schema) -> bool { + if exprs.len() != schema.fields().len() { + return false; + } + exprs.iter().enumerate().all(|(i, expr)| { + if let Expr::Column(col) = expr { + schema.index_of(col.name()).ok() == Some(i) + } else { + false + } + }) +} +``` + +**IMPORTANT:** Do NOT add filter classification logic. The existing filter handling (filters passed to source, Filter nodes for unsupported) should remain unchanged. + +### 5. `datafusion/expr/src/logical_plan/builder.rs` + +Update any scan building code to work with the new projection type. + +### 6. `datafusion/proto/src/logical_plan/mod.rs` + +Update serialization/deserialization for the new projection type. + +### 7. `datafusion/sql/src/unparser/plan.rs` and `utils.rs` + +Update SQL unparsing to handle expression-based projections. + +### 8. `datafusion/substrait/` + +Update Substrait conversion in: +- `src/logical_plan/consumer/rel/read_rel.rs` +- `src/logical_plan/producer/rel/read_rel.rs` + +### 9. `datafusion/optimizer/src/push_down_filter.rs` + +**Minimal changes only** - just update test helpers to use new projection type: + +```rust +// In test helper functions, convert projection indices to expressions +let projection_exprs = projection.map(|indices| { + indices.into_iter().map(|i| { + let field = schema.field(i); + Expr::Column(Column::new(Some("test"), field.name())) + }).collect::>() +}); +``` + +**DO NOT** change the filter classification logic. Keep `supports_filters_pushdown()` call and Filter node creation. + +### 10. Test Files (`.slt` files) + +Update expected plans to show projection expressions on TableScan. The key change in plan output: +- Before: `TableScan: test projection=[0, 1]` +- After: `TableScan: test projection=[a, b]` + +**Keep Filter nodes in expected outputs** - filter consolidation happens in PR B. + +--- + +## Implementation Steps + +1. Create branch from main: + ```bash + git checkout main + git pull origin main + git checkout -b projection-expressions + ``` + +2. Implement TableScan struct changes and TableScanBuilder + +3. Update optimize_projections to work with expressions + +4. Update physical planner with simplified plan_table_scan + +5. Update serialization (proto, substrait) + +6. Update SQL unparser + +7. Fix push_down_filter test helpers only + +8. Update test expected outputs + +9. Run tests: + ```bash + cargo test -p datafusion-expr + cargo test -p datafusion-optimizer + cargo test -p datafusion-core + cargo test -p datafusion-sqllogictest + ``` + +10. Create PR: + ```bash + git add -A + git commit -m "Change TableScan.projection to use expressions instead of column indices" + git push -u origin projection-expressions + ``` + +--- + +## PR Description + +```markdown +## Summary +Changes `TableScan.projection` from `Option>` to `Option>`, +allowing projection expressions to be represented directly on the TableScan node. + +## Changes +- Modified `TableScan` struct to use expression-based projections +- Added `TableScanBuilder` for constructing scans with expression projections +- Updated `optimize_projections` to work with expressions +- Physical planner creates `ProjectionExec` when projection isn't identity +- Backward compatible: `TableScan::try_new()` still accepts indices + +## Why This Change +This is preparation for richer scan optimizations and enables representing +computed columns directly on table scans. + +## Test Plan +- All existing tests pass with updated expected outputs +- Verified projection expressions work correctly with various scan patterns +``` + +--- + +## Key Differences from Original PR #20061 + +1. **No filter consolidation** - filters stay in optimizer, not deferred to physical planner +2. **No compute_scan_projection()** that considers filters - not needed since filters are Filter nodes +3. **No FilterExec creation** in plan_table_scan - existing behavior preserved +4. **Keep Filter nodes in test outputs** - they're not removed until PR B diff --git a/struct.parquet b/struct.parquet new file mode 100644 index 0000000000000..b9b87acae2121 Binary files /dev/null and b/struct.parquet differ diff --git a/table_scan_refactor.md b/table_scan_refactor.md new file mode 100644 index 0000000000000..76b35025079f3 --- /dev/null +++ b/table_scan_refactor.md @@ -0,0 +1,563 @@ +# TableScan Physical Planning Refactor + +## Goal + +Refactor TableScan physical planning so that **all** filter and projection handling happens during physical planning, not during logical optimization. This eliminates the need for separate `Filter` and `Projection` logical nodes above `TableScan`. + +### Current Structure +``` +Projection(exprs) → ProjectionExec + └─ Filter(predicate) → FilterExec + └─ TableScan(filters=[...]) → +``` + +### Target Structure +``` +TableScan(projection=[exprs], filters=[all_filters]) + ↓ physical planning +ProjectionExec + └─ FilterExec (for Inexact/Unsupported filters) + └─ +``` + +--- + +## Current Implementation + +### 1. TableScan Struct + +**File:** `datafusion/expr/src/logical_plan/plan.rs:2680-2693` + +```rust +pub struct TableScan { + pub table_name: TableReference, + pub source: Arc, + pub projection: Option>, // Column indices + pub projected_schema: DFSchemaRef, + pub filters: Vec, // Only Exact+Inexact filters (not Unsupported) + pub fetch: Option, +} +``` + +### 2. Filter Pushdown (Optimizer Phase) + +**File:** `datafusion/optimizer/src/push_down_filter.rs:1128-1185` + +Currently, the `PushDownFilter` optimizer rule: +1. Calls `source.supports_filters_pushdown()` to check each filter +2. Moves Exact+Inexact filters into `TableScan.filters` +3. Keeps Inexact+Unsupported filters in a `Filter` node above + +```rust +LogicalPlan::TableScan(scan) => { + let filter_predicates = split_conjunction(&filter.predicate); + + // Check which filters are supported + let supported_filters = scan.source + .supports_filters_pushdown(non_volatile_filters.as_slice())?; + + // Exact + Inexact → go to TableScan.filters + let new_scan_filters = zip.clone() + .filter(|(_, res)| res != &TableProviderFilterPushDown::Unsupported) + .map(|(pred, _)| pred); + + // Inexact + Unsupported → stay in Filter node above (DUPLICATES Inexact!) + let new_predicate: Vec = zip + .filter(|(_, res)| res != &TableProviderFilterPushDown::Exact) + .map(|(pred, _)| pred) + .chain(volatile_filters) + .cloned() + .collect(); + + let new_scan = LogicalPlan::TableScan(TableScan { + filters: new_scan_filters, + ..scan + }); + + // Add Filter node above if there are remaining predicates + if let Some(predicate) = conjunction(new_predicate) { + make_filter(predicate, Arc::new(new_scan)) + } else { + new_scan + } +} +``` + +**Nit with current state:** Inexact filters are duplicated - they appear in both `TableScan.filters` AND the `Filter` node above. + +### 3. Physical Planning (Current) + +**File:** `datafusion/core/src/physical_planner.rs:458-477` + +TableScan conversion just passes filters through to the provider: + +```rust +LogicalPlan::TableScan(TableScan { + source, + projection, + filters, + fetch, + .. +}) => { + let source = source_as_provider(source)?; + let filters = unnormalize_cols(filters.iter().cloned()); + let filters_vec = filters.into_iter().collect::>(); + let opts = ScanArgs::default() + .with_projection(projection.as_deref()) + .with_filters(Some(&filters_vec)) + .with_limit(*fetch); + let res = source.scan_with_args(session_state, opts).await?; + Arc::clone(res.plan()) +} +``` + +**File:** `datafusion/core/src/physical_planner.rs:949-1005` + +Filter nodes are converted separately to FilterExec: + +```rust +LogicalPlan::Filter(Filter { predicate, input, .. }) => { + let physical_input = children.one()?; + let runtime_expr = self.create_physical_expr(predicate, input_dfschema, session_state)?; + FilterExecBuilder::new(Arc::clone(&runtime_expr[0]), physical_input) + .with_batch_size(session_state.config().batch_size()) + .build()? +} +``` + +### 4. TableProvider Trait + +**File:** `datafusion/catalog/src/table.rs:285-293` + +```rust +fn supports_filters_pushdown( + &self, + filters: &[&Expr], +) -> Result> { + // Default: all filters unsupported + Ok(vec![TableProviderFilterPushDown::Unsupported; filters.len()]) +} +``` + +**File:** `datafusion/expr/src/table_source.rs:37-51` + +```rust +pub enum TableProviderFilterPushDown { + Unsupported, // Cannot handle, need FilterExec above + Inexact, // Can handle but may return extra rows, need FilterExec above + Exact, // Guarantees correct filtering, no FilterExec needed +} +``` + +--- + +## Proposed Changes + +### 1. Modify TableScan Struct + +**File:** `datafusion/expr/src/logical_plan/plan.rs` + +Change `projection` from `Vec` to `Vec`: + +```rust +pub struct TableScan { + pub table_name: TableReference, + pub source: Arc, + pub projection: Option>, // CHANGED: Expression projections + pub projected_schema: DFSchemaRef, + pub filters: Vec, // Now contains ALL filters (Exact+Inexact+Unsupported) + pub fetch: Option, +} +``` + +### 2. Add TableScanBuilder with Expression Projections + +**File:** `datafusion/expr/src/logical_plan/plan.rs:2767-2815` + +To support building with expression projections, and instead of adding a new constructor with many parameters, add a builder struct: + +```rust +pub struct TableScanBuilder { + table_name: TableReference, + table_source: Arc, + projection: Option>, + filters: Vec, + fetch: Option, +} + +impl TableScanBuilder { + pub fn new( + table_name: impl Into, + table_source: Arc, + ) -> Self { + Self { + table_name: table_name.into(), + table_source, + projection: None, + filters: vec![], + fetch: None, + } + } + + pub fn with_projection(mut self, projection: Vec) -> Self { + self.projection = Some(projection); + self + } + + pub fn with_filters(mut self, filters: Vec) -> Self { + self.filters = filters; + self + } + + pub fn with_fetch(mut self, fetch: usize) -> Self { + self.fetch = Some(fetch); + self + } + + pub fn build(self) -> Result { + ensure_valid_table_name(&self.table_name)?; + + let schema = self.table_source.schema(); + + // Compute projected_schema from expressions + let projected_schema = match &self.projection { + Some(exprs) => { + let source_dfschema = DFSchema::try_from_qualified_schema( + self.table_name.clone(), + &schema + )?; + // Use exprlist_to_fields to compute output schema from expressions + let fields = exprlist_to_fields(exprs, &source_dfschema)?; + DFSchema::new_with_metadata(fields, schema.metadata.clone())? + } + None => { + DFSchema::try_from_qualified_schema(self.table_name.clone(), &schema)? + } + }; + + Ok(TableScan { + table_name: self.table_name, + source: self.table_source, + projection: self.projection, + projected_schema: Arc::new(projected_schema), + filters: self.filters, + fetch: self.fetch, + }) + } +} +``` + +Update `try_new()` to use the builder: + +```rust +/// Create TableScan with column indices (for backward compatibility) +pub fn try_new( + table_name: impl Into, + table_source: Arc, + projection: Option>, + filters: Vec, + fetch: Option, +) -> Result { + let schema = table_source.schema(); + + // Convert indices to column expressions + let projection_exprs = projection.map(|indices| { + indices.iter().map(|&idx| { + let field = schema.field(idx); + col(Column::new_unqualified(field.name())) + }).collect() + }); + + let mut builder = TableScanBuilder::new(table_name, table_source) + .with_filters(filters) + .with_fetch(fetch.unwrap_or_default()); + if let Some(exprs) = projection_exprs { + builder = builder.with_projection(exprs); + } + builder.build() +} +``` + +### 4. Refactor Physical Planner + +**File:** `datafusion/core/src/physical_planner.rs:458-477` + +Replace the current TableScan handling with: + +```rust +LogicalPlan::TableScan(TableScan { + table_name, + source, + projection, + projected_schema, + filters, + fetch, +}) => { + let source = source_as_provider(source)?; + let source_schema = source.schema(); + + // === STEP 1: Determine filter pushdown support === + let filter_refs: Vec<&Expr> = filters.iter().collect(); + let pushdown_support = source.supports_filters_pushdown(&filter_refs)?; + + // Filters to pass to provider (Exact + Inexact) + let provider_filters: Vec = filters.iter() + .zip(pushdown_support.iter()) + .filter(|(_, support)| **support != TableProviderFilterPushDown::Unsupported) + .map(|(f, _)| f.clone()) + .collect(); + + // Filters that need FilterExec above (Inexact + Unsupported) + let post_scan_filters: Vec = filters.iter() + .zip(pushdown_support.iter()) + .filter(|(_, support)| **support != TableProviderFilterPushDown::Exact) + .map(|(f, _)| f.clone()) + .collect(); + + // === STEP 2: Compute column indices needed from source === + // Union of columns referenced by projection exprs + post_scan_filters + let source_indices = compute_required_columns( + projection.as_ref(), + &post_scan_filters, + &source_schema, + ); + + // === STEP 3: Call provider's scan === + let provider_filters_unnorm = unnormalize_cols(provider_filters.into_iter()); + let provider_filters_vec: Vec = provider_filters_unnorm.collect(); + + let opts = ScanArgs::default() + .with_projection(Some(&source_indices)) + .with_filters(Some(&provider_filters_vec)) + .with_limit(*fetch); + + let scan_result = source.scan_with_args(session_state, opts).await?; + let mut result: Arc = Arc::clone(scan_result.plan()); + + // === STEP 4: Wrap with FilterExec if needed === + if !post_scan_filters.is_empty() { + let post_filters_unnorm: Vec = unnormalize_cols(post_scan_filters.into_iter()).collect(); + let predicate = conjunction(post_filters_unnorm).unwrap(); + + // Create physical expression for the filter + // Note: Need to use the scan output schema here + let scan_schema = result.schema(); + let physical_predicate = self.create_physical_expr( + &predicate, + &DFSchema::try_from(scan_schema.as_ref().clone())?, + session_state, + )?; + + result = Arc::new( + FilterExecBuilder::new(physical_predicate, result) + .with_batch_size(session_state.config().batch_size()) + .build()? + ); + } + + // === STEP 5: Wrap with ProjectionExec if needed === + if let Some(exprs) = &projection { + // Check if projection is just column references matching scan output + if !is_identity_projection(exprs, result.schema()) { + let physical_exprs: Vec<(Arc, String)> = exprs.iter() + .map(|e| { + let phys = self.create_physical_expr( + e, + projected_schema.as_ref(), + session_state, + )?; + let name = e.schema_name().to_string(); + Ok((phys, name)) + }) + .collect::>>()?; + + result = Arc::new(ProjectionExec::try_new(physical_exprs, result)?); + } + } + + result +} +``` + +### 5. Helper Functions to Add + +**File:** `datafusion/core/src/physical_planner.rs` (or a new utils module) + +```rust +/// Extract all column references from projection expressions and filters. +/// Returns sorted unique column indices needed from source schema. +fn compute_required_columns( + projection: Option<&Vec>, + filters: &[Expr], + source_schema: &SchemaRef, +) -> Vec { + let mut columns = BTreeSet::new(); + + // Collect columns from projection expressions + if let Some(exprs) = projection { + for expr in exprs { + expr.apply(|e| { + if let Expr::Column(col) = e { + if let Ok(idx) = source_schema.index_of(col.name()) { + columns.insert(idx); + } + } + Ok(TreeNodeRecursion::Continue) + }).ok(); + } + } else { + // No projection = all columns + columns.extend(0..source_schema.fields().len()); + } + + // Collect columns from filters (all filters, not just pushed ones) + for expr in filters { + expr.apply(|e| { + if let Expr::Column(col) = e { + if let Ok(idx) = source_schema.index_of(col.name()) { + columns.insert(idx); + } + } + Ok(TreeNodeRecursion::Continue) + }).ok(); + } + + columns.into_iter().collect() +} + +/// Check if projection is just selecting columns in order (identity) +fn is_identity_projection(exprs: &[Expr], schema: &SchemaRef) -> bool { + if exprs.len() != schema.fields().len() { + return false; + } + + exprs.iter().enumerate().all(|(i, expr)| { + matches!(expr, Expr::Column(col) if col.name() == schema.field(i).name()) + }) +} +``` + +### 6. Update PushDownFilter Optimizer + +**File:** `datafusion/optimizer/src/push_down_filter.rs:1128-1185` + +Simplify to just move ALL filters into TableScan without checking pushdown support: + +```rust +LogicalPlan::TableScan(scan) => { + let filter_predicates = split_conjunction(&filter.predicate); + + // Move ALL filters to TableScan.filters (pushdown decision deferred to physical planning) + let new_scan_filters: Vec = scan.filters + .iter() + .chain(filter_predicates.iter().cloned()) + .unique() + .cloned() + .collect(); + + // No Filter node above - all filters now in TableScan + Transformed::yes(LogicalPlan::TableScan(TableScan { + filters: new_scan_filters, + ..scan + })) +} +``` + +**Note:** This removes the call to `supports_filters_pushdown()` from the optimizer. That call now happens in the physical planner. + +### 7. Update OptimizeProjections + +**File:** `datafusion/optimizer/src/optimize_projections/mod.rs:255-274` + +Update to merge Projection nodes into TableScan: + +```rust +LogicalPlan::Projection(projection) => { + if let LogicalPlan::TableScan(scan) = projection.input.as_ref() { + // TODO: Merge existing scan.projection with new projection.expr + // E.g. if TableScan::projection = [col("b") + col("c") as "bc"] + // and Projection::expr = [col("bc") * 2 as "bc2"] + // then we need to rewrite the projection into TableScan as: + // [ (col("b") + col("c")) * 2 as "bc2" ] + let merged_projection = todo!("Merge projection expressions into TableScan") + + let new_scan = TableScanBuilder::new( + scan.table_name.clone(), + Arc::clone(&scan.source), + ) + .with_projection(merged_projection) + .with_filters(scan.filters.clone()) + .with_fetch(scan.fetch) + .build()?; + + return Ok(Transformed::yes(LogicalPlan::TableScan(new_scan))); + } + // ... existing projection handling for non-TableScan inputs +} + +LogicalPlan::TableScan(table_scan) => { + // Update projection to only include required columns/expressions + let new_projection = match &table_scan.projection { + Some(exprs) => { + Some(indices.iter().map(|&idx| exprs[idx].clone()).collect()) + } + None => { + let schema = table_scan.source.schema(); + Some(indices.iter().map(|&idx| { + let field = schema.field(idx); + col(Column::new(Some(table_scan.table_name.clone()), field.name())) + }).collect()) + } + }; + + let new_scan = TableScan::try_new( + table_scan.table_name.clone(), + Arc::clone(&table_scan.source), + new_projection, + table_scan.filters.clone(), + table_scan.fetch, + )?; + + Ok(Transformed::yes(LogicalPlan::TableScan(new_scan))) +} +``` + +--- + +## Files to Modify + +| File | Changes | +|------|---------| +| `datafusion/expr/src/logical_plan/plan.rs` | Change `projection: Option>` to `Option>`, update `try_new()`, add `try_new_with_indices()` | +| `datafusion/core/src/physical_planner.rs` | Rewrite TableScan handling to add FilterExec + ProjectionExec, add helper functions | +| `datafusion/optimizer/src/push_down_filter.rs` | Simplify to move all filters to TableScan without checking pushdown | +| `datafusion/optimizer/src/optimize_projections/mod.rs` | Update to handle `Vec` projections, merge Projection into TableScan | +| `datafusion/expr/src/logical_plan/builder.rs` | Update builder methods to use new constructors | + +--- + +## Testing Strategy + +1. **Unit tests for new helper functions:** + - `compute_required_columns()` + - `is_identity_projection()` + +2. **Integration tests:** + - Query with filter that is `Exact` → no FilterExec above scan + - Query with filter that is `Inexact` → FilterExec above scan + - Query with filter that is `Unsupported` → FilterExec above scan, filter not passed to provider + - Query with expression projection → ProjectionExec above scan + - Query with column-only projection → no ProjectionExec (identity) + +3. **Existing tests:** + - Run `cargo test -p datafusion-core` + - Run `cargo test -p datafusion-optimizer` + - Many tests will need updating due to changed plan structure + +--- + +## Migration Notes + +- The `Filter` logical node will still exist for filters above non-TableScan nodes +- Existing `TableProvider` implementations don't need changes - they still receive filters via `ScanArgs` +- The `supports_filters_pushdown()` method is now called during physical planning instead of optimization diff --git a/test_sort_aggregate.sql b/test_sort_aggregate.sql new file mode 100644 index 0000000000000..3a024285f7c39 --- /dev/null +++ b/test_sort_aggregate.sql @@ -0,0 +1,15 @@ +-- Test query for sort injection rule +-- This aggregate has multiple grouping keys which should trigger sort injection + +CREATE TABLE events ( + timestamp INT, + trace_id INT, + category STRING, + amount FLOAT +); + +-- Verify the query plan shows a Sort before the Aggregate +EXPLAIN VERBOSE +SELECT timestamp, trace_id, category, COUNT(*) as cnt, SUM(amount) as total +FROM events +GROUP BY timestamp, trace_id, category;