(args: &[ast::Expr], catalog: &dyn SqlCatalog)
| 235 | } |
| 236 | |
| 237 | fn plan_elementwise(args: &[ast::Expr], catalog: &dyn SqlCatalog) -> Result<SqlPlan> { |
| 238 | if args.len() != 4 { |
| 239 | return Err(SqlError::Unsupported { |
| 240 | detail: format!( |
| 241 | "ARRAY_ELEMENTWISE expects 4 args (left, right, op, attr); got {}", |
| 242 | args.len() |
| 243 | ), |
| 244 | }); |
| 245 | } |
| 246 | let left = require_array_name(args, 0, "ARRAY_ELEMENTWISE", catalog)?; |
| 247 | let right = require_array_name(args, 1, "ARRAY_ELEMENTWISE", catalog)?; |
| 248 | let lview = catalog |
| 249 | .lookup_array(&left) |
| 250 | .ok_or_else(|| SqlError::Unsupported { |
| 251 | detail: format!("ARRAY_ELEMENTWISE: array '{left}' not found"), |
| 252 | })?; |
| 253 | let rview = catalog |
| 254 | .lookup_array(&right) |
| 255 | .ok_or_else(|| SqlError::Unsupported { |
| 256 | detail: format!("ARRAY_ELEMENTWISE: array '{right}' not found"), |
| 257 | })?; |
| 258 | if lview.dims.len() != rview.dims.len() || lview.attrs.len() != rview.attrs.len() { |
| 259 | return Err(SqlError::Unsupported { |
| 260 | detail: format!( |
| 261 | "ARRAY_ELEMENTWISE: arrays '{left}' and '{right}' must share schema shape" |
| 262 | ), |
| 263 | }); |
| 264 | } |
| 265 | let op_str = expect_string_literal(&args[2], "ARRAY_ELEMENTWISE op")?; |
| 266 | let op = ArrayBinaryOpAst::parse(&op_str).ok_or_else(|| SqlError::Unsupported { |
| 267 | detail: format!("ARRAY_ELEMENTWISE: unknown op '{op_str}' (want add/sub/mul/div)"), |
| 268 | })?; |
| 269 | let attr = expect_string_literal(&args[3], "ARRAY_ELEMENTWISE attr")?; |
| 270 | if !lview.attrs.iter().any(|a| a.name == attr) { |
| 271 | return Err(SqlError::Unsupported { |
| 272 | detail: format!("ARRAY_ELEMENTWISE: array '{left}' has no attr '{attr}'"), |
| 273 | }); |
| 274 | } |
| 275 | Ok(SqlPlan::ArrayElementwise { |
| 276 | left, |
| 277 | right, |
| 278 | op, |
| 279 | attr, |
| 280 | }) |
| 281 | } |
no test coverage detected