Backing implementation for sql_impl_func and sql_impl_cast. See those functions for details.
(
expr: &str,
)
| 344 | /// Backing implementation for sql_impl_func and sql_impl_cast. See those |
| 345 | /// functions for details. |
| 346 | pub fn sql_impl( |
| 347 | expr: &str, |
| 348 | ) -> impl Fn(&ExprContext, Vec<SqlScalarType>) -> Result<HirScalarExpr, PlanError> + use<> { |
| 349 | let expr = mz_sql_parser::parser::parse_expr(expr).unwrap_or_else(|e| { |
| 350 | panic!( |
| 351 | "static function definition failed to parse {}: {}", |
| 352 | expr.quoted(), |
| 353 | e, |
| 354 | ) |
| 355 | }); |
| 356 | move |ecx, types| { |
| 357 | // Reconstruct an expression context where the parameter types are |
| 358 | // bound to the types of the expressions in `args`. |
| 359 | let mut scx = ecx.qcx.scx.clone(); |
| 360 | scx.param_types = RefCell::new( |
| 361 | types |
| 362 | .into_iter() |
| 363 | .enumerate() |
| 364 | .map(|(i, ty)| (i + 1, ty)) |
| 365 | .collect(), |
| 366 | ); |
| 367 | let qcx = QueryContext::root(&scx, ecx.qcx.lifetime); |
| 368 | |
| 369 | let (mut expr, new_ids) = names::resolve(qcx.scx.catalog, expr.clone())?; |
| 370 | scx.sql_impl_resolved_ids |
| 371 | .lock() |
| 372 | .expect("planning is single-threaded") |
| 373 | .extend_from(&new_ids); |
| 374 | // Desugar the expression |
| 375 | transform_ast::transform(&scx, &mut expr)?; |
| 376 | |
| 377 | let ecx_name = format!( |
| 378 | "static function definition (or its outer context '{}')", |
| 379 | ecx.name |
| 380 | ); |
| 381 | let ecx = ExprContext { |
| 382 | qcx: &qcx, |
| 383 | name: ecx_name.as_str(), |
| 384 | scope: &Scope::empty(), |
| 385 | relation_type: &SqlRelationType::empty(), |
| 386 | // Constrain the new context by the outer context's `allow_subqueries`. |
| 387 | // (We could potentially to the same for `allow_aggregates` and `allow_windows`, I just |
| 388 | // don't want to think these through until we have a concrete use case.) |
| 389 | // (`allow_parameters` we have to set true, because that is the machinery for function |
| 390 | // arguments, i.e., parameters from in here won't escape `sql_impl_func` or |
| 391 | // `sql_impl_cast`.) |
| 392 | allow_aggregates: false, |
| 393 | allow_subqueries: ecx.allow_subqueries, |
| 394 | allow_parameters: true, |
| 395 | allow_windows: false, |
| 396 | }; |
| 397 | |
| 398 | // Plan the expression. |
| 399 | query::plan_expr(&ecx, &expr)?.type_as_any(&ecx) |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | // Constructs a definition for a built-in function out of a static SQL |
no test coverage detected