Plans a `VALUES` clause that appears at the top level of an `INSERT` statement. This is special-cased in PostgreSQL and different enough from `plan_values` that it is easier to use a separate function entirely. Unlike a normal `VALUES` clause, each value is coerced to the type of the target table via an assignment cast. See: <https://github.com/postgres/postgres/blob/ad77039fa/src/backend/parser
(
qcx: &QueryContext,
target_names: &[&ColumnName],
target_types: &[&SqlScalarType],
values: &[Vec<Expr<Aug>>],
)
| 2157 | /// |
| 2158 | /// See: <https://github.com/postgres/postgres/blob/ad77039fa/src/backend/parser/analyze.c#L504-L518> |
| 2159 | fn plan_values_insert( |
| 2160 | qcx: &QueryContext, |
| 2161 | target_names: &[&ColumnName], |
| 2162 | target_types: &[&SqlScalarType], |
| 2163 | values: &[Vec<Expr<Aug>>], |
| 2164 | ) -> Result<HirRelationExpr, PlanError> { |
| 2165 | assert!(!values.is_empty()); |
| 2166 | |
| 2167 | if !values.iter().map(|row| row.len()).all_equal() { |
| 2168 | sql_bail!("VALUES lists must all be the same length"); |
| 2169 | } |
| 2170 | |
| 2171 | let ecx = &ExprContext { |
| 2172 | qcx, |
| 2173 | name: "VALUES", |
| 2174 | scope: &Scope::empty(), |
| 2175 | relation_type: &SqlRelationType::empty(), |
| 2176 | allow_aggregates: false, |
| 2177 | allow_subqueries: true, |
| 2178 | allow_parameters: true, |
| 2179 | allow_windows: false, |
| 2180 | }; |
| 2181 | |
| 2182 | let mut exprs = vec![]; |
| 2183 | let mut types = vec![]; |
| 2184 | for row in values { |
| 2185 | if row.len() > target_names.len() { |
| 2186 | sql_bail!("INSERT has more expressions than target columns"); |
| 2187 | } |
| 2188 | for (column, val) in row.into_iter().enumerate() { |
| 2189 | let target_type = &target_types[column]; |
| 2190 | let val = plan_expr(ecx, val)?; |
| 2191 | let val = typeconv::plan_coerce(ecx, val, target_type)?; |
| 2192 | let source_type = &ecx.scalar_type(&val); |
| 2193 | let val = match typeconv::plan_cast(ecx, CastContext::Assignment, val, target_type) { |
| 2194 | Ok(val) => val, |
| 2195 | Err(_) => sql_bail!( |
| 2196 | "column {} is of type {} but expression is of type {}", |
| 2197 | target_names[column].quoted(), |
| 2198 | qcx.humanize_sql_scalar_type(target_type, false), |
| 2199 | qcx.humanize_sql_scalar_type(source_type, false), |
| 2200 | ), |
| 2201 | }; |
| 2202 | if column >= types.len() { |
| 2203 | types.push(ecx.column_type(&val)); |
| 2204 | } else { |
| 2205 | types[column] = types[column].sql_union(&ecx.column_type(&val))?; // HIR deliberately not using `union` |
| 2206 | } |
| 2207 | exprs.push(val); |
| 2208 | } |
| 2209 | } |
| 2210 | |
| 2211 | Ok(HirRelationExpr::CallTable { |
| 2212 | func: TableFunc::Wrap { |
| 2213 | width: values[0].len(), |
| 2214 | types, |
| 2215 | }, |
| 2216 | exprs, |
no test coverage detected