Adjust `get` to perform an existential subquery on `using` accounting for `selection`. If `USING`, we essentially want to rewrite the query as a correlated existential subquery, i.e. ``` ...WHERE EXISTS (SELECT 1 FROM WHERE ) ``` However, we can't do that directly because of esoteric rules w/r/t `lateral` subqueries. https://github.com/postgres/postgres/commit/158b7fa6a34006bdc
(
qcx: &QueryContext,
selection: Option<Expr<Aug>>,
using: Vec<TableWithJoins<Aug>>,
get: HirRelationExpr,
outer_scope: Scope,
)
| 850 | // subqueries. |
| 851 | // https://github.com/postgres/postgres/commit/158b7fa6a34006bdc70b515e14e120d3e896589b |
| 852 | fn handle_mutation_using_clause( |
| 853 | qcx: &QueryContext, |
| 854 | selection: Option<Expr<Aug>>, |
| 855 | using: Vec<TableWithJoins<Aug>>, |
| 856 | get: HirRelationExpr, |
| 857 | outer_scope: Scope, |
| 858 | ) -> Result<HirRelationExpr, PlanError> { |
| 859 | // Plan `USING` as a cross-joined `FROM` without knowledge of the |
| 860 | // statement's `FROM` target. This prevents `lateral` subqueries from |
| 861 | // "seeing" the `FROM` target. |
| 862 | let (mut using_rel_expr, using_scope) = |
| 863 | using.into_iter().try_fold(plan_join_identity(), |l, twj| { |
| 864 | let (left, left_scope) = l; |
| 865 | plan_join( |
| 866 | qcx, |
| 867 | left, |
| 868 | left_scope, |
| 869 | &Join { |
| 870 | relation: TableFactor::NestedJoin { |
| 871 | join: Box::new(twj), |
| 872 | alias: None, |
| 873 | }, |
| 874 | join_operator: JoinOperator::CrossJoin, |
| 875 | }, |
| 876 | ) |
| 877 | })?; |
| 878 | |
| 879 | if let Some(expr) = selection { |
| 880 | // Join `FROM` with `USING` tables, like `USING..., FROM`. This gives us |
| 881 | // PG-like semantics e.g. expressing ambiguous column references. We put |
| 882 | // `USING...` first for no real reason, but making a different decision |
| 883 | // would require adjusting the column references on this relation |
| 884 | // differently. |
| 885 | let on = HirScalarExpr::literal_true(); |
| 886 | let joined = using_rel_expr |
| 887 | .clone() |
| 888 | .join(get.clone(), on, JoinKind::Inner); |
| 889 | let joined_scope = using_scope.product(outer_scope)?; |
| 890 | let joined_relation_type = qcx.relation_type(&joined); |
| 891 | |
| 892 | let ecx = &ExprContext { |
| 893 | qcx, |
| 894 | name: "WHERE clause", |
| 895 | scope: &joined_scope, |
| 896 | relation_type: &joined_relation_type, |
| 897 | allow_aggregates: false, |
| 898 | allow_subqueries: true, |
| 899 | allow_parameters: true, |
| 900 | allow_windows: false, |
| 901 | }; |
| 902 | |
| 903 | // Plan the filter expression on `FROM, USING...`. |
| 904 | let mut expr = plan_expr(ecx, &expr)?.type_as(ecx, &SqlScalarType::Bool)?; |
| 905 | |
| 906 | // Rewrite all column referring to the `FROM` section of `joined` (i.e. |
| 907 | // those to the right of `using_rel_expr`) to instead be correlated to |
| 908 | // the outer relation, i.e. `get`. |
| 909 | let using_rel_arity = qcx.relation_type(&using_rel_expr).arity(); |
no test coverage detected