icydb-core 0.94.0

IcyDB — A schema-first typed query engine and persistence runtime for Internet Computer canisters
Documentation
use super::{
    SqlProjectionMaterializationMetrics, materialize::project_structural_sql_projection_page,
    with_sql_projection_materialization_metrics,
};

use crate::{
    db::{
        executor::{
            PreparedProjectionPlan, StructuralCursorPage, projection::PreparedProjectionShape,
            projection_eval_data_row_for_materialize_tests,
            projection_eval_row_layout_for_materialize_tests, terminal::RetainedSlotRow,
        },
        query::plan::expr::{Expr, FieldId, ProjectionField, ProjectionSpec},
    },
    value::Value,
};

fn direct_rank_projection_shape() -> PreparedProjectionShape {
    PreparedProjectionShape::from_test_parts(
        ProjectionSpec::from_fields_for_test(vec![ProjectionField::Scalar {
            expr: Expr::Field(FieldId::new("rank")),
            alias: None,
        }]),
        PreparedProjectionPlan::Scalar(Vec::new()),
        false,
        Some(vec![("rank".to_string(), 1)]),
        Some(vec![("rank".to_string(), 1)]),
        vec![false, true, false, false],
    )
}

fn repeated_direct_rank_projection_shape() -> PreparedProjectionShape {
    PreparedProjectionShape::from_test_parts(
        ProjectionSpec::from_fields_for_test(vec![
            ProjectionField::Scalar {
                expr: Expr::Field(FieldId::new("rank")),
                alias: None,
            },
            ProjectionField::Scalar {
                expr: Expr::Field(FieldId::new("rank")),
                alias: None,
            },
        ]),
        PreparedProjectionPlan::Scalar(Vec::new()),
        false,
        None,
        Some(vec![("rank".to_string(), 1), ("rank".to_string(), 1)]),
        vec![false, true, false, false],
    )
}

fn expect_projection_metrics<T>(f: impl FnOnce() -> T) -> (T, SqlProjectionMaterializationMetrics) {
    with_sql_projection_materialization_metrics(f)
}

#[test]
fn sql_projection_materialization_prefers_retained_slot_rows() {
    let row_layout = projection_eval_row_layout_for_materialize_tests();
    let page = StructuralCursorPage::new_with_slot_rows(
        vec![RetainedSlotRow::new(4, vec![(1, Value::Int(19))])],
        None,
    );
    let prepared_projection = direct_rank_projection_shape();

    let (payload, metrics) = expect_projection_metrics(|| {
        project_structural_sql_projection_page(row_layout, &prepared_projection, page)
    });
    let payload = payload.expect("slot-row SQL projection materialization should succeed");

    assert_eq!(payload, vec![vec![Value::Int(19)]]);

    assert_eq!(
        metrics.slot_rows_path_hits, 1,
        "slot-row projection should stay on the retained-slot path",
    );
    assert_eq!(
        metrics.data_rows_path_hits, 0,
        "slot-row projection should not reopen raw data rows",
    );
    assert_eq!(
        metrics.data_rows_scalar_fallback_hits, 0,
        "slot-row projection should avoid the scalar data-row fallback",
    );
    assert_eq!(
        metrics.full_row_decode_materializations, 0,
        "slot-row projection should not trigger eager full-row decode",
    );
}

#[test]
fn sql_projection_materialization_prefers_direct_data_row_field_copies() {
    let row_layout = projection_eval_row_layout_for_materialize_tests();
    let page = StructuralCursorPage::new(
        vec![projection_eval_data_row_for_materialize_tests(41, 19, true)],
        None,
    );
    let prepared_projection = direct_rank_projection_shape();

    let (payload, metrics) = expect_projection_metrics(|| {
        project_structural_sql_projection_page(row_layout, &prepared_projection, page)
    });
    let payload = payload.expect("data-row SQL projection materialization should succeed");

    assert_eq!(payload, vec![vec![Value::Int(19)]]);

    assert_eq!(
        metrics.data_rows_path_hits, 1,
        "data-row projection should stay on the raw-row path",
    );
    assert_eq!(
        metrics.data_rows_scalar_fallback_hits, 0,
        "direct data-row field copies should avoid the scalar fallback path",
    );
    assert_eq!(
        metrics.data_rows_projected_slot_accesses, 1,
        "direct data-row field copies should decode only the declared projected slot",
    );
    assert_eq!(
        metrics.data_rows_non_projected_slot_accesses, 0,
        "direct data-row field copies should avoid unrelated slot reads",
    );
}

#[test]
fn sql_projection_materialization_prefers_direct_data_row_field_copies_for_repeated_fields() {
    let row_layout = projection_eval_row_layout_for_materialize_tests();
    let page = StructuralCursorPage::new(
        vec![projection_eval_data_row_for_materialize_tests(41, 19, true)],
        None,
    );
    let prepared_projection = repeated_direct_rank_projection_shape();

    let (payload, metrics) = expect_projection_metrics(|| {
        project_structural_sql_projection_page(row_layout, &prepared_projection, page)
    });
    let payload = payload.expect("repeated data-row SQL projection materialization should succeed");

    assert_eq!(payload, vec![vec![Value::Int(19), Value::Int(19)]]);

    assert_eq!(
        metrics.data_rows_path_hits, 1,
        "repeated data-row projection should stay on the raw-row path",
    );
    assert_eq!(
        metrics.data_rows_scalar_fallback_hits, 0,
        "repeated direct data-row fields should avoid the scalar fallback path",
    );
    assert_eq!(
        metrics.data_rows_projected_slot_accesses, 2,
        "repeated direct data-row fields should read only the repeated projected slot",
    );
    assert_eq!(
        metrics.data_rows_non_projected_slot_accesses, 0,
        "repeated direct data-row fields should avoid unrelated slot reads",
    );
}