1use std::sync::Arc;
5
6use reifydb_core::{
7 error::diagnostic::catalog::{dictionary_not_found, namespace_not_found},
8 interface::catalog::{
9 config::{ConfigKey, GetConfig},
10 policy::{DataOp, PolicyTargetType},
11 },
12 value::column::{ColumnWithName, buffer::ColumnBuffer, columns::Columns},
13};
14use reifydb_evaluate::stack::SymbolTable;
15use reifydb_rql::nodes::InsertDictionaryNode;
16use reifydb_transaction::transaction::Transaction;
17use reifydb_value::{
18 fragment::Fragment,
19 params::Params,
20 return_error,
21 value::{Value, dictionary::DictionaryEntryId, value_type::ValueType},
22};
23
24use super::returning::evaluate_returning;
25use crate::{
26 Result,
27 policy::PolicyEvaluator,
28 transaction::operation::dictionary::DictionaryOperations,
29 vm::{
30 services::Services,
31 volcano::{
32 compile::compile,
33 query::{QueryContext, QueryNode, query_budget},
34 },
35 },
36};
37
38pub(crate) fn insert_dictionary(
39 services: &Arc<Services>,
40 txn: &mut Transaction<'_>,
41 plan: InsertDictionaryNode,
42 symbols: &mut SymbolTable,
43) -> Result<Columns> {
44 let namespace_name = plan.target.namespace().name();
45
46 let Some(namespace) = services.catalog.find_namespace_by_name(txn, namespace_name)? else {
47 return_error!(namespace_not_found(Fragment::internal(namespace_name), namespace_name));
48 };
49
50 let dictionary_name = plan.target.name();
51 let Some(dictionary) = services.catalog.find_dictionary_by_name(txn, namespace.id(), dictionary_name)? else {
52 let fragment = plan.target.identifier().clone();
53 return_error!(dictionary_not_found(fragment.clone(), namespace_name, dictionary_name,));
54 };
55
56 let execution_context = Arc::new(QueryContext {
57 services: services.clone(),
58 source: None,
59 batch_size: services.catalog.get_config_uint2(ConfigKey::QueryRowBatchSize) as u64,
60 params: Params::None,
61 symbols: symbols.clone(),
62 identity: txn.identity(),
63 memory: query_budget(services),
64 });
65
66 let mut input_node = compile(*plan.input, txn, execution_context.clone());
67
68 input_node.initialize(txn, &execution_context)?;
69
70 let mut ids: Vec<Value> = Vec::new();
71 let mut values: Vec<Value> = Vec::new();
72 let mut mutable_context = (*execution_context).clone();
73
74 while let Some(columns) = input_node.next(txn, &mut mutable_context)? {
75 PolicyEvaluator::new(services, symbols).enforce_write_policies(
76 txn,
77 namespace_name,
78 dictionary_name,
79 DataOp::Insert,
80 &columns,
81 PolicyTargetType::Dictionary,
82 )?;
83
84 let row_count = columns.row_count();
85
86 for row_idx in 0..row_count {
87 let value = if let Some(value_column) = columns.iter().find(|col| col.name() == "value") {
88 value_column.data().get_value(row_idx)
89 } else if let Some(first_column) = columns.iter().next() {
90 first_column.data().get_value(row_idx)
91 } else {
92 Value::none()
93 };
94
95 if matches!(value, Value::None { .. }) {
96 continue;
97 }
98
99 let coerced_value = coerce_value_to_dictionary_type(value, dictionary.value_type.clone())?;
100
101 let entry_id = txn.insert_into_dictionary(&dictionary, &coerced_value)?;
102
103 let id_value = match entry_id {
104 DictionaryEntryId::U1(v) => Value::Uint1(v),
105 DictionaryEntryId::U2(v) => Value::Uint2(v),
106 DictionaryEntryId::U4(v) => Value::Uint4(v),
107 DictionaryEntryId::U8(v) => Value::Uint8(v),
108 DictionaryEntryId::U16(v) => Value::Uint16(v),
109 };
110
111 ids.push(id_value);
112 values.push(coerced_value);
113 }
114 }
115
116 if let Some(returning_exprs) = &plan.returning {
117 if ids.is_empty() {
118 return evaluate_returning(
119 services,
120 symbols,
121 returning_exprs,
122 Columns::empty(),
123 txn.identity(),
124 );
125 }
126 let id_column = build_id_column(&ids, dictionary.id_type)?;
127 let value_column = build_value_column(&values, dictionary.value_type)?;
128 let columns = Columns::new(vec![id_column, value_column]);
129 return evaluate_returning(services, symbols, returning_exprs, columns, txn.identity());
130 }
131
132 if ids.is_empty() {
133 return Ok(Columns::new(vec![
134 ColumnWithName::new(
135 Fragment::internal("namespace"),
136 ColumnBuffer::utf8(vec![namespace.name()]),
137 ),
138 ColumnWithName::new(
139 Fragment::internal("dictionary"),
140 ColumnBuffer::utf8(vec![dictionary.name.clone()]),
141 ),
142 ColumnWithName::new(Fragment::internal("inserted"), ColumnBuffer::uint8(vec![0])),
143 ]));
144 }
145
146 let id_column = build_id_column(&ids, dictionary.id_type)?;
147
148 let value_column = build_value_column(&values, dictionary.value_type)?;
149
150 Ok(Columns::new(vec![
151 ColumnWithName::new(
152 Fragment::internal("namespace"),
153 ColumnBuffer::utf8(vec![namespace.name(); ids.len()]),
154 ),
155 ColumnWithName::new(
156 Fragment::internal("dictionary"),
157 ColumnBuffer::utf8(vec![dictionary.name.clone(); ids.len()]),
158 ),
159 id_column,
160 value_column,
161 ]))
162}
163
164fn coerce_value_to_dictionary_type(value: Value, target_type: ValueType) -> Result<Value> {
165 match (&value, target_type) {
166 (Value::Utf8(_), ValueType::Utf8) => Ok(value),
167 (Value::Int1(_), ValueType::Int1) => Ok(value),
168 (Value::Int2(_), ValueType::Int2) => Ok(value),
169 (Value::Int4(_), ValueType::Int4) => Ok(value),
170 (Value::Int8(_), ValueType::Int8) => Ok(value),
171 (Value::Int16(_), ValueType::Int16) => Ok(value),
172 (Value::Uint1(_), ValueType::Uint1) => Ok(value),
173 (Value::Uint2(_), ValueType::Uint2) => Ok(value),
174 (Value::Uint4(_), ValueType::Uint4) => Ok(value),
175 (Value::Uint8(_), ValueType::Uint8) => Ok(value),
176 (Value::Uint16(_), ValueType::Uint16) => Ok(value),
177 (Value::Float4(_), ValueType::Float4) => Ok(value),
178 (Value::Float8(_), ValueType::Float8) => Ok(value),
179 (Value::Boolean(_), ValueType::Boolean) => Ok(value),
180 (Value::Date(_), ValueType::Date) => Ok(value),
181 (Value::DateTime(_), ValueType::DateTime) => Ok(value),
182 (Value::Time(_), ValueType::Time) => Ok(value),
183 (Value::Duration(_), ValueType::Duration) => Ok(value),
184 (Value::Uuid4(_), ValueType::Uuid4) => Ok(value),
185 (Value::Uuid7(_), ValueType::Uuid7) => Ok(value),
186 (Value::Blob(_), ValueType::Blob) => Ok(value),
187 (Value::Decimal(_), ValueType::Decimal) => Ok(value),
188 _ => Ok(value),
190 }
191}
192
193fn build_id_column(ids: &[Value], id_type: ValueType) -> Result<ColumnWithName> {
194 let data = match id_type {
195 ValueType::Uint1 => {
196 let vals: Vec<u8> = ids
197 .iter()
198 .map(|v| match v {
199 Value::Uint1(n) => *n,
200 _ => 0,
201 })
202 .collect();
203 ColumnBuffer::uint1(vals)
204 }
205 ValueType::Uint2 => {
206 let vals: Vec<u16> = ids
207 .iter()
208 .map(|v| match v {
209 Value::Uint2(n) => *n,
210 _ => 0,
211 })
212 .collect();
213 ColumnBuffer::uint2(vals)
214 }
215 ValueType::Uint4 => {
216 let vals: Vec<u32> = ids
217 .iter()
218 .map(|v| match v {
219 Value::Uint4(n) => *n,
220 _ => 0,
221 })
222 .collect();
223 ColumnBuffer::uint4(vals)
224 }
225 ValueType::Uint8 => {
226 let vals: Vec<u64> = ids
227 .iter()
228 .map(|v| match v {
229 Value::Uint8(n) => *n,
230 _ => 0,
231 })
232 .collect();
233 ColumnBuffer::uint8(vals)
234 }
235 ValueType::Uint16 => {
236 let vals: Vec<u128> = ids
237 .iter()
238 .map(|v| match v {
239 Value::Uint16(n) => *n,
240 _ => 0,
241 })
242 .collect();
243 ColumnBuffer::uint16(vals)
244 }
245 _ => {
246 let vals: Vec<u64> = ids
247 .iter()
248 .map(|v| match v {
249 Value::Uint8(n) => *n,
250 _ => 0,
251 })
252 .collect();
253 ColumnBuffer::uint8(vals)
254 }
255 };
256
257 Ok(ColumnWithName {
258 name: Fragment::internal("id"),
259 data,
260 })
261}
262
263fn build_value_column(values: &[Value], value_type: ValueType) -> Result<ColumnWithName> {
264 let data = match value_type {
265 ValueType::Utf8 => {
266 let vals: Vec<String> = values
267 .iter()
268 .map(|v| match v {
269 Value::Utf8(s) => s.clone(),
270 _ => format!("{:?}", v),
271 })
272 .collect();
273 ColumnBuffer::utf8(vals)
274 }
275 ValueType::Int1 => {
276 let vals: Vec<i8> = values
277 .iter()
278 .map(|v| match v {
279 Value::Int1(n) => *n,
280 _ => 0,
281 })
282 .collect();
283 ColumnBuffer::int1(vals)
284 }
285 ValueType::Int2 => {
286 let vals: Vec<i16> = values
287 .iter()
288 .map(|v| match v {
289 Value::Int2(n) => *n,
290 _ => 0,
291 })
292 .collect();
293 ColumnBuffer::int2(vals)
294 }
295 ValueType::Int4 => {
296 let vals: Vec<i32> = values
297 .iter()
298 .map(|v| match v {
299 Value::Int4(n) => *n,
300 _ => 0,
301 })
302 .collect();
303 ColumnBuffer::int4(vals)
304 }
305 ValueType::Int8 => {
306 let vals: Vec<i64> = values
307 .iter()
308 .map(|v| match v {
309 Value::Int8(n) => *n,
310 _ => 0,
311 })
312 .collect();
313 ColumnBuffer::int8(vals)
314 }
315 ValueType::Uint1 => {
316 let vals: Vec<u8> = values
317 .iter()
318 .map(|v| match v {
319 Value::Uint1(n) => *n,
320 _ => 0,
321 })
322 .collect();
323 ColumnBuffer::uint1(vals)
324 }
325 ValueType::Uint2 => {
326 let vals: Vec<u16> = values
327 .iter()
328 .map(|v| match v {
329 Value::Uint2(n) => *n,
330 _ => 0,
331 })
332 .collect();
333 ColumnBuffer::uint2(vals)
334 }
335 ValueType::Uint4 => {
336 let vals: Vec<u32> = values
337 .iter()
338 .map(|v| match v {
339 Value::Uint4(n) => *n,
340 _ => 0,
341 })
342 .collect();
343 ColumnBuffer::uint4(vals)
344 }
345 ValueType::Uint8 => {
346 let vals: Vec<u64> = values
347 .iter()
348 .map(|v| match v {
349 Value::Uint8(n) => *n,
350 _ => 0,
351 })
352 .collect();
353 ColumnBuffer::uint8(vals)
354 }
355 _ => {
356 let vals: Vec<String> = values.iter().map(|v| format!("{:?}", v)).collect();
357 ColumnBuffer::utf8(vals)
358 }
359 };
360
361 Ok(ColumnWithName {
362 name: Fragment::internal("value"),
363 data,
364 })
365}