algeon-datafusion 0.1.2

DataFusion physical-plan adapter for native GPU execution.
Documentation
use super::*;
use crate::native::ParquetReadStrategyConfig;

#[test]
fn adapter_validation_rejects_like_over_non_string_input() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-like-type-reject");
    let path = dir.join("input.parquet");
    write_numeric_parquet_file(&path);
    let scan = parquet_scan(&path);
    let scan_schema = scan.schema();
    let predicate: Arc<dyn PhysicalExpr> = Arc::new(LikeExpr::new(
        false,
        false,
        col("payload", &scan_schema).unwrap(),
        lit(ScalarValue::Utf8(Some("1%".to_string()))),
    ));
    let plan = aggregate_sort_limit_plan_with_filter(scan, predicate, Operator::Plus);

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert!(matches!(
        result.report.outcomes()[0],
        CandidateOutcome::NotSupported { capability_reason: CapabilityReason::UnsupportedType, .. }
    ));

    fs::remove_dir_all(dir).unwrap();
}

#[test]
fn adapter_validation_lowers_date64_projection() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-date64-projection");
    let path = dir.join("input.parquet");
    write_date64_parquet_file(&path);
    let scan = parquet_scan(&path);
    let scan_schema = scan.schema();
    let plan: Arc<dyn ExecutionPlan> = Arc::new(
        ProjectionExec::try_new(
            [
                ProjectionExpr { expr: col("event_date64", &scan_schema).unwrap(), alias: "event_date64".to_string() },
                ProjectionExpr { expr: col("m00", &scan_schema).unwrap(), alias: "m00".to_string() },
            ],
            scan,
        )
        .unwrap(),
    );

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    let source = native_local_parquet_source(result.selected_plan());
    assert_eq!(source.read_columns, vec!["event_date64".to_string(), "m00".to_string()]);
    assert!(source.diagnostics.rejected_features.is_empty());

    fs::remove_dir_all(dir).unwrap();
}

#[tokio::test]
async fn adapter_validation_rejects_extract_over_date64_until_expression_semantics_exist() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-date64-extract-reject");
    let path = dir.join("input.parquet");
    write_date64_parquet_file(&path);
    let plan = sql_plan(&path, direct_friendly_sql_session_config(), SQL_DATE64_EXTRACT_QUERY).await;

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert!(matches!(
        result.report.outcomes()[0],
        CandidateOutcome::NotSupported { capability_reason: CapabilityReason::UnsupportedType, .. }
    ));

    fs::remove_dir_all(dir).unwrap();
}

#[test]
fn pushed_scan_projection_reads_only_downstream_required_columns() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-scan-projection-pruning");
    let path = dir.join("input.parquet");
    write_numeric_parquet_file(&path);
    let scan = parquet_scan_with_projection_indices(&path, vec![0, 1, 2, 3]);
    let plan = aggregate_sort_limit_plan_without_filter(scan, Operator::Plus);

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    let source = native_local_parquet_source(result.selected_plan());
    assert_eq!(source.read_columns, vec!["key".to_string(), "m00".to_string(), "m01".to_string()]);
    assert!(!source.read_columns.contains(&"payload".to_string()));
    assert_eq!(source.diagnostics.read_column_count, 3);

    fs::remove_dir_all(dir).unwrap();
}

#[tokio::test]
async fn scalar_expression_filter_predicate_required_source_columns_are_exact() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-scalar_expression-filter-columns");
    let path = dir.join("input.parquet");
    write_parquet_file_with_tpch_like_columns(&path);
    let plan =
        sql_plan(&path, direct_friendly_sql_session_config(), SQL_SOURCE_COLUMN_FILTER_REQUIRED_COLUMNS_QUERY).await;

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    let source = native_local_parquet_source(result.selected_plan());
    assert_eq!(source.read_columns, vec!["key".to_string(), "label".to_string(), "m00".to_string(), "m01".to_string()]);
    assert_eq!(source.projected_output_columns, vec!["key".to_string(), "m00".to_string(), "m01".to_string()]);
    assert_eq!(source.pure_filter_columns, vec!["label".to_string()]);
    assert_eq!(source.diagnostics.read_column_count, 4);
    assert_eq!(source.diagnostics.projected_output_column_count, 3);
    assert_eq!(source.diagnostics.pure_filter_column_count, 1);
    assert!(!source.read_columns.contains(&"payload".to_string()));
    assert!(!source.read_columns.contains(&"amount".to_string()));

    fs::remove_dir_all(dir).unwrap();
}

#[tokio::test]
async fn scalar_expression_pre_aggregate_projection_required_source_columns_are_exact() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-scalar_expression-pre-projection-columns");
    let path = dir.join("input.parquet");
    write_parquet_file_with_tpch_like_columns(&path);
    let plan =
        sql_plan(&path, direct_friendly_sql_session_config(), SQL_SOURCE_COLUMN_PRE_PROJECTION_REQUIRED_COLUMNS_QUERY)
            .await;

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    let source = native_local_parquet_source(result.selected_plan());
    assert_eq!(source.read_columns, vec!["key".to_string(), "label".to_string(), "m00".to_string(), "m01".to_string()]);
    assert!(source.pure_filter_columns.is_empty());
    for unused in ["payload", "amount", "shipdate", "event_ts"] {
        assert!(!source.read_columns.contains(&unused.to_string()));
    }

    fs::remove_dir_all(dir).unwrap();
}

#[tokio::test]
async fn scalar_expression_aggregate_argument_required_source_columns_are_exact() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-scalar_expression-aggregate-argument-columns");
    let path = dir.join("input.parquet");
    write_parquet_file_with_tpch_like_columns(&path);
    let plan = sql_plan(
        &path,
        direct_friendly_sql_session_config(),
        SQL_SOURCE_COLUMN_AGGREGATE_ARGUMENT_REQUIRED_COLUMNS_QUERY,
    )
    .await;

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    let source = native_local_parquet_source(result.selected_plan());
    assert_eq!(source.read_columns, vec!["key".to_string(), "label".to_string(), "m00".to_string(), "m01".to_string()]);
    let aggregate_exprs = native_aggregate_exprs(result.selected_plan());
    assert_eq!(aggregate_exprs.len(), 1);
    assert!(matches!(
        &aggregate_exprs[0].expr,
        Expr::Column(column) if column.name().starts_with("__algeon_native_aggregate_arg_")
    ));
    assert!(!source.read_columns.contains(&"payload".to_string()));

    fs::remove_dir_all(dir).unwrap();
}

#[tokio::test]
async fn nullif_aggregate_argument_reads_both_operand_columns() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-nullif-aggregate-argument-columns");
    let path = dir.join("input.parquet");
    write_numeric_parquet_file(&path);
    let plan =
        sql_plan(&path, direct_friendly_sql_session_config(), SQL_SOURCE_COLUMN_NULLIF_ARGUMENT_REQUIRED_COLUMNS_QUERY)
            .await;

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    let source = native_local_parquet_source(result.selected_plan());
    assert_eq!(source.read_columns, vec!["key".to_string(), "m00".to_string(), "m01".to_string()]);
    assert!(!source.read_columns.contains(&"payload".to_string()));

    fs::remove_dir_all(dir).unwrap();
}

#[tokio::test]
async fn scalar_expression_group_expression_required_source_columns_are_exact() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-scalar_expression-group-expression-columns");
    let path = dir.join("input.parquet");
    write_parquet_file_with_tpch_like_columns(&path);
    let plan =
        sql_plan(&path, direct_friendly_sql_session_config(), SQL_SOURCE_COLUMN_GROUP_REQUIRED_COLUMNS_QUERY).await;

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    let source = native_local_parquet_source(result.selected_plan());
    assert_eq!(source.read_columns, vec!["label".to_string(), "m00".to_string(), "shipdate".to_string()]);
    for unused in ["key", "payload", "m01", "amount", "event_ts"] {
        assert!(!source.read_columns.contains(&unused.to_string()));
    }

    fs::remove_dir_all(dir).unwrap();
}

#[tokio::test]
async fn pushed_scan_projection_prunes_payload_for_nested_scalar_expression_scalars() {
    let dir = unique_temp_dir("algeon-datafusion-native-lowering-scalar_expression-scan-projection-columns");
    let path = dir.join("input.parquet");
    write_parquet_file_with_tpch_like_columns(&path);
    let plan = sql_plan(
        &path,
        direct_friendly_sql_session_config(),
        SQL_SOURCE_COLUMN_PUSHED_PROJECTION_REQUIRED_COLUMNS_QUERY,
    )
    .await;

    let result = lower_physical_plan_to_native(plan, &ParquetReadStrategyConfig::default()).unwrap();

    assert_eq!(result.selected_count(), 1, "outcomes={:?}", result.report.outcomes());
    assert_eq!(result.not_selected_count(), 0, "outcomes={:?}", result.report.outcomes());
    let source = native_local_parquet_source(result.selected_plan());
    assert_eq!(source.read_columns, vec!["label".to_string(), "m00".to_string(), "shipdate".to_string()]);
    assert_eq!(source.read_column_file_indices, vec![4, 2, 6]);
    assert!(!source.read_columns.contains(&"payload".to_string()));
    assert!(!source.read_columns.contains(&"amount".to_string()));

    fs::remove_dir_all(dir).unwrap();
}