Skip to main content

nodedb_sql/planner/join/
array_arm.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! ARRAY_* table-valued function as a JOIN source.
4//!
5//! When a JOIN's left or right relation is `ARRAY_SLICE(...)` (or
6//! sibling read TVFs), the planner lowers it to the corresponding
7//! `SqlPlan::Array*` variant directly — bypassing catalog lookup.
8//! The TVF's output rows participate in the join key resolution like
9//! any other relation; the dispatch handler emits `(coords, attrs)`
10//! tuples that include the array's surrogate-equivalent identity
11//! columns so equi-join keys work naturally.
12
13use sqlparser::ast;
14
15use crate::error::Result;
16use crate::temporal::TemporalScope;
17use crate::types::{SqlCatalog, SqlPlan};
18
19/// If `rel` is a `ARRAY_*(...)` TVF call, return the corresponding
20/// `SqlPlan::Array*` node. Otherwise return `Ok(None)` so the caller
21/// falls through to the named-table scan path.
22pub(super) fn try_plan_relation(
23    rel: &ast::TableFactor,
24    catalog: &dyn SqlCatalog,
25    temporal: TemporalScope,
26) -> Result<Option<SqlPlan>> {
27    let name = match rel {
28        ast::TableFactor::Table {
29            name,
30            args: Some(_),
31            ..
32        } => name,
33        _ => return Ok(None),
34    };
35    let fn_name = crate::parser::normalize::normalize_object_name_checked(name)?;
36    if !is_array_tvf(&fn_name) {
37        return Ok(None);
38    }
39
40    // Reuse the SELECT * FROM ARRAY_*(...) planner by wrapping the
41    // single relation into a one-element TableWithJoins. Both call
42    // sites need exactly the same validation (arg arity, schema
43    // resolution, dim/attr name checks) — re-deriving it here would
44    // duplicate that logic and let the two paths drift.
45    let twj = ast::TableWithJoins {
46        relation: rel.clone(),
47        joins: Vec::new(),
48    };
49    super::super::array_fn::try_plan_array_table_fn(std::slice::from_ref(&twj), catalog, temporal)
50}
51
52fn is_array_tvf(name: &str) -> bool {
53    matches!(
54        name,
55        "array_slice" | "array_project" | "array_agg" | "array_elementwise"
56    )
57}