Plans a `ROWS FROM` expression. `ROWS FROM` concatenates table functions into a single table, filling in `NULL`s in places where one table function has fewer rows than another. We can achieve this by augmenting each table function with a row number, doing a `FULL JOIN` between each table function on the row number and eventually projecting away the row number columns. Concretely, the following qu
(
qcx: &QueryContext,
functions: &[Function<Aug>],
alias: Option<&TableAlias>,
with_ordinality: bool,
)
| 3080 | /// `with_ordinality` can be used to have the output expression contain a |
| 3081 | /// single coalesced ordinality column at the end of the entire expression. |
| 3082 | fn plan_rows_from( |
| 3083 | qcx: &QueryContext, |
| 3084 | functions: &[Function<Aug>], |
| 3085 | alias: Option<&TableAlias>, |
| 3086 | with_ordinality: bool, |
| 3087 | ) -> Result<(HirRelationExpr, Scope), PlanError> { |
| 3088 | // The `repeat_row` function is not supported in ROWS FROM. |
| 3089 | if functions.iter().any(is_repeat_row) { |
| 3090 | // Note: Would be also caught by WITH ORDINALITY checking for `repeat_row`, but then the |
| 3091 | // error message would be misleading, because it would refer to WITH ORDINALITY instead of |
| 3092 | // ROWS FROM. |
| 3093 | bail_unsupported!(format!("{} in ROWS FROM", REPEAT_ROW_NAME)); |
| 3094 | } |
| 3095 | |
| 3096 | // If there's only a single table function, planning proceeds as if `ROWS |
| 3097 | // FROM` hadn't been written at all. |
| 3098 | if let [function] = functions { |
| 3099 | return plan_solitary_table_function(qcx, function, alias, with_ordinality); |
| 3100 | } |
| 3101 | |
| 3102 | // Per PostgreSQL, all scope items take the name of the first function |
| 3103 | // (unless aliased). |
| 3104 | // See: https://github.com/postgres/postgres/blob/639a86e36/src/backend/parser/parse_relation.c#L1701-L1705 |
| 3105 | let (expr, mut scope, num_cols) = plan_rows_from_internal( |
| 3106 | qcx, |
| 3107 | functions, |
| 3108 | Some(functions[0].name.full_item_name().clone()), |
| 3109 | )?; |
| 3110 | |
| 3111 | // Columns tracks the set of columns we will keep in the projection. |
| 3112 | let mut columns = Vec::new(); |
| 3113 | let mut offset = 0; |
| 3114 | // Retain table function's non-ordinality columns. |
| 3115 | for (idx, cols) in num_cols.into_iter().enumerate() { |
| 3116 | for i in 0..cols { |
| 3117 | columns.push(offset + i); |
| 3118 | } |
| 3119 | offset += cols + 1; |
| 3120 | |
| 3121 | // Remove the ordinality column from the scope, accounting for previous scope |
| 3122 | // changes from this loop. |
| 3123 | scope.items.remove(offset - idx - 1); |
| 3124 | } |
| 3125 | |
| 3126 | // If `WITH ORDINALITY` was specified, include the coalesced ordinality |
| 3127 | // column. Otherwise remove it from the scope. |
| 3128 | if with_ordinality { |
| 3129 | columns.push(offset); |
| 3130 | } else { |
| 3131 | scope.items.pop(); |
| 3132 | } |
| 3133 | |
| 3134 | let expr = expr.project(columns); |
| 3135 | |
| 3136 | let scope = plan_table_alias(scope, alias)?; |
| 3137 | Ok((expr, scope)) |
| 3138 | } |
| 3139 |
no test coverage detected