(mut scope: Scope, alias: Option<&TableAlias>)
| 3438 | } |
| 3439 | |
| 3440 | fn plan_table_alias(mut scope: Scope, alias: Option<&TableAlias>) -> Result<Scope, PlanError> { |
| 3441 | if let Some(TableAlias { |
| 3442 | name, |
| 3443 | columns, |
| 3444 | strict, |
| 3445 | }) = alias |
| 3446 | { |
| 3447 | if (columns.len() > scope.items.len()) || (*strict && columns.len() != scope.items.len()) { |
| 3448 | sql_bail!( |
| 3449 | "{} has {} columns available but {} columns specified", |
| 3450 | name, |
| 3451 | scope.items.len(), |
| 3452 | columns.len() |
| 3453 | ); |
| 3454 | } |
| 3455 | |
| 3456 | let table_name = normalize::ident(name.to_owned()); |
| 3457 | for (i, item) in scope.items.iter_mut().enumerate() { |
| 3458 | item.table_name = if item.allow_unqualified_references { |
| 3459 | Some(PartialItemName { |
| 3460 | database: None, |
| 3461 | schema: None, |
| 3462 | item: table_name.clone(), |
| 3463 | }) |
| 3464 | } else { |
| 3465 | // Columns that prohibit unqualified references are special |
| 3466 | // columns from the output of a NATURAL or USING join that can |
| 3467 | // only be referenced by their full, pre-join name. Applying an |
| 3468 | // alias to the output of that join renders those columns |
| 3469 | // inaccessible, which we accomplish here by setting the |
| 3470 | // table name to `None`. |
| 3471 | // |
| 3472 | // Concretely, consider: |
| 3473 | // |
| 3474 | // CREATE TABLE t1 (a int); |
| 3475 | // CREATE TABLE t2 (a int); |
| 3476 | // (1) SELECT ... FROM (t1 NATURAL JOIN t2); |
| 3477 | // (2) SELECT ... FROM (t1 NATURAL JOIN t2) AS t; |
| 3478 | // |
| 3479 | // In (1), the join has no alias. The underlying columns from |
| 3480 | // either side of the join can be referenced as `t1.a` and |
| 3481 | // `t2.a`, respectively, and the unqualified name `a` refers to |
| 3482 | // a column whose value is `coalesce(t1.a, t2.a)`. |
| 3483 | // |
| 3484 | // In (2), the join is aliased as `t`. The columns from either |
| 3485 | // side of the join (`t1.a` and `t2.a`) are inaccessible, and |
| 3486 | // the coalesced column can be named as either `a` or `t.a`. |
| 3487 | // |
| 3488 | // We previously had a bug [0] that mishandled this subtle |
| 3489 | // logic. |
| 3490 | // |
| 3491 | // NOTE(benesch): We could in theory choose to project away |
| 3492 | // those inaccessible columns and drop them from the scope |
| 3493 | // entirely, but that would require that this function also |
| 3494 | // take and return the `HirRelationExpr` that is being aliased, |
| 3495 | // which is a rather large refactor. |
| 3496 | // |
| 3497 | // [0]: https://github.com/MaterializeInc/database-issues/issues/4887 |
no test coverage detected