If `rel` is a `ARRAY_*(...)` TVF call, return the corresponding `SqlPlan::Array*` node. Otherwise return `Ok(None)` so the caller falls through to the named-table scan path.
(
rel: &ast::TableFactor,
catalog: &dyn SqlCatalog,
temporal: TemporalScope,
)
| 20 | /// `SqlPlan::Array*` node. Otherwise return `Ok(None)` so the caller |
| 21 | /// falls through to the named-table scan path. |
| 22 | pub(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 | |
| 52 | fn is_array_tvf(name: &str) -> bool { |
| 53 | matches!( |
no test coverage detected