Skip to main content

reifydb_engine/bulk_insert/
coerce.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4//! Column coercion for bulk inserts.
5
6use reifydb_core::{
7	interface::catalog::column::ColumnDef,
8	value::column::{columns::Columns, data::ColumnData},
9};
10use reifydb_function::registry::Functions;
11use reifydb_runtime::clock::Clock;
12use reifydb_type::{fragment::Fragment, params::Params};
13
14use crate::{
15	expression::{cast::cast_column_data, context::EvalContext},
16	vm::stack::SymbolTable,
17};
18
19/// Coerce each column's data to the target type in batch.
20pub(super) fn coerce_columns(
21	column_data: &[ColumnData],
22	columns: &[ColumnDef],
23	num_rows: usize,
24) -> crate::Result<Vec<ColumnData>> {
25	let ctx = EvalContext {
26		target: None,
27		columns: Columns::empty(),
28		row_count: num_rows,
29		take: None,
30		params: &Params::None,
31		symbol_table: &SymbolTable::new(),
32		is_aggregate_context: false,
33		functions: &Functions::empty(),
34		clock: &Clock::default(),
35		arena: None,
36	};
37
38	let mut coerced_columns: Vec<ColumnData> = Vec::with_capacity(columns.len());
39
40	for (col_idx, col) in columns.iter().enumerate() {
41		let target = col.constraint.get_type();
42		// For Option(T) columns, cast to the inner type T; None values pass through unchanged
43		let cast_target = target.inner_type().clone();
44		let source_data = &column_data[col_idx];
45
46		let coerced = cast_column_data(&ctx, source_data, cast_target, || Fragment::internal(&col.name))?;
47		coerced_columns.push(coerced);
48	}
49
50	Ok(coerced_columns)
51}