Skip to main content

reifydb_function/math/scalar/
clamp.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use num_traits::ToPrimitive;
5use reifydb_core::value::column::{Column, columns::Columns, data::ColumnData};
6use reifydb_type::{
7	fragment::Fragment,
8	value::{container::number::NumberContainer, decimal::Decimal, int::Int, r#type::Type, uint::Uint},
9};
10
11use crate::{
12	ScalarFunction, ScalarFunctionContext,
13	error::{ScalarFunctionError, ScalarFunctionResult},
14	propagate_options,
15};
16
17pub struct Clamp;
18
19impl Clamp {
20	pub fn new() -> Self {
21		Self
22	}
23}
24
25fn convert_column_to_type(data: &ColumnData, target: Type, row_count: usize) -> ColumnData {
26	match target {
27		Type::Int1 => {
28			let mut result = Vec::with_capacity(row_count);
29			let mut bitvec = Vec::with_capacity(row_count);
30			for i in 0..row_count {
31				if data.is_defined(i) {
32					result.push(get_as_i8(data, i));
33					bitvec.push(true);
34				} else {
35					result.push(0);
36					bitvec.push(false);
37				}
38			}
39			ColumnData::int1_with_bitvec(result, bitvec)
40		}
41		Type::Int2 => {
42			let mut result = Vec::with_capacity(row_count);
43			let mut bitvec = Vec::with_capacity(row_count);
44			for i in 0..row_count {
45				if data.is_defined(i) {
46					result.push(get_as_i16(data, i));
47					bitvec.push(true);
48				} else {
49					result.push(0);
50					bitvec.push(false);
51				}
52			}
53			ColumnData::int2_with_bitvec(result, bitvec)
54		}
55		Type::Int4 => {
56			let mut result = Vec::with_capacity(row_count);
57			let mut bitvec = Vec::with_capacity(row_count);
58			for i in 0..row_count {
59				if data.is_defined(i) {
60					result.push(get_as_i32(data, i));
61					bitvec.push(true);
62				} else {
63					result.push(0);
64					bitvec.push(false);
65				}
66			}
67			ColumnData::int4_with_bitvec(result, bitvec)
68		}
69		Type::Int8 => {
70			let mut result = Vec::with_capacity(row_count);
71			let mut bitvec = Vec::with_capacity(row_count);
72			for i in 0..row_count {
73				if data.is_defined(i) {
74					result.push(get_as_i64(data, i));
75					bitvec.push(true);
76				} else {
77					result.push(0);
78					bitvec.push(false);
79				}
80			}
81			ColumnData::int8_with_bitvec(result, bitvec)
82		}
83		Type::Int16 => {
84			let mut result = Vec::with_capacity(row_count);
85			let mut bitvec = Vec::with_capacity(row_count);
86			for i in 0..row_count {
87				if data.is_defined(i) {
88					result.push(get_as_i128(data, i));
89					bitvec.push(true);
90				} else {
91					result.push(0);
92					bitvec.push(false);
93				}
94			}
95			ColumnData::int16_with_bitvec(result, bitvec)
96		}
97		Type::Uint1 => {
98			let mut result = Vec::with_capacity(row_count);
99			let mut bitvec = Vec::with_capacity(row_count);
100			for i in 0..row_count {
101				if data.is_defined(i) {
102					result.push(get_as_u8(data, i));
103					bitvec.push(true);
104				} else {
105					result.push(0);
106					bitvec.push(false);
107				}
108			}
109			ColumnData::uint1_with_bitvec(result, bitvec)
110		}
111		Type::Uint2 => {
112			let mut result = Vec::with_capacity(row_count);
113			let mut bitvec = Vec::with_capacity(row_count);
114			for i in 0..row_count {
115				if data.is_defined(i) {
116					result.push(get_as_u16(data, i));
117					bitvec.push(true);
118				} else {
119					result.push(0);
120					bitvec.push(false);
121				}
122			}
123			ColumnData::uint2_with_bitvec(result, bitvec)
124		}
125		Type::Uint4 => {
126			let mut result = Vec::with_capacity(row_count);
127			let mut bitvec = Vec::with_capacity(row_count);
128			for i in 0..row_count {
129				if data.is_defined(i) {
130					result.push(get_as_u32(data, i));
131					bitvec.push(true);
132				} else {
133					result.push(0);
134					bitvec.push(false);
135				}
136			}
137			ColumnData::uint4_with_bitvec(result, bitvec)
138		}
139		Type::Uint8 => {
140			let mut result = Vec::with_capacity(row_count);
141			let mut bitvec = Vec::with_capacity(row_count);
142			for i in 0..row_count {
143				if data.is_defined(i) {
144					result.push(get_as_u64(data, i));
145					bitvec.push(true);
146				} else {
147					result.push(0);
148					bitvec.push(false);
149				}
150			}
151			ColumnData::uint8_with_bitvec(result, bitvec)
152		}
153		Type::Uint16 => {
154			let mut result = Vec::with_capacity(row_count);
155			let mut bitvec = Vec::with_capacity(row_count);
156			for i in 0..row_count {
157				if data.is_defined(i) {
158					result.push(get_as_u128(data, i));
159					bitvec.push(true);
160				} else {
161					result.push(0);
162					bitvec.push(false);
163				}
164			}
165			ColumnData::uint16_with_bitvec(result, bitvec)
166		}
167		Type::Float4 => {
168			let mut result = Vec::with_capacity(row_count);
169			let mut bitvec = Vec::with_capacity(row_count);
170			for i in 0..row_count {
171				if data.is_defined(i) {
172					result.push(get_as_f32(data, i));
173					bitvec.push(true);
174				} else {
175					result.push(0.0);
176					bitvec.push(false);
177				}
178			}
179			ColumnData::float4_with_bitvec(result, bitvec)
180		}
181		Type::Float8 => {
182			let mut result = Vec::with_capacity(row_count);
183			let mut bitvec = Vec::with_capacity(row_count);
184			for i in 0..row_count {
185				if data.is_defined(i) {
186					result.push(get_as_f64(data, i));
187					bitvec.push(true);
188				} else {
189					result.push(0.0);
190					bitvec.push(false);
191				}
192			}
193			ColumnData::float8_with_bitvec(result, bitvec)
194		}
195		Type::Int => {
196			let mut result = Vec::with_capacity(row_count);
197			let mut bitvec = Vec::with_capacity(row_count);
198			for i in 0..row_count {
199				if data.is_defined(i) {
200					result.push(Int::from(get_as_i128(data, i)));
201					bitvec.push(true);
202				} else {
203					result.push(Int::default());
204					bitvec.push(false);
205				}
206			}
207			ColumnData::int_with_bitvec(result, bitvec)
208		}
209		Type::Uint => {
210			let mut result = Vec::with_capacity(row_count);
211			let mut bitvec = Vec::with_capacity(row_count);
212			for i in 0..row_count {
213				if data.is_defined(i) {
214					result.push(Uint::from(get_as_u128(data, i)));
215					bitvec.push(true);
216				} else {
217					result.push(Uint::default());
218					bitvec.push(false);
219				}
220			}
221			ColumnData::uint_with_bitvec(result, bitvec)
222		}
223		Type::Decimal => {
224			let mut result = Vec::with_capacity(row_count);
225			let mut bitvec = Vec::with_capacity(row_count);
226			for i in 0..row_count {
227				if data.is_defined(i) {
228					result.push(Decimal::from(get_as_f64(data, i)));
229					bitvec.push(true);
230				} else {
231					result.push(Decimal::default());
232					bitvec.push(false);
233				}
234			}
235			ColumnData::decimal_with_bitvec(result, bitvec)
236		}
237		_ => data.clone(),
238	}
239}
240
241fn get_as_i8(data: &ColumnData, i: usize) -> i8 {
242	match data {
243		ColumnData::Int1(c) => c.get(i).copied().unwrap_or(0),
244		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i8).unwrap_or(0),
245		_ => 0,
246	}
247}
248
249fn get_as_u8(data: &ColumnData, i: usize) -> u8 {
250	match data {
251		ColumnData::Uint1(c) => c.get(i).copied().unwrap_or(0),
252		ColumnData::Int1(c) => c.get(i).map(|&v| v as u8).unwrap_or(0),
253		_ => 0,
254	}
255}
256
257fn get_as_i16(data: &ColumnData, i: usize) -> i16 {
258	match data {
259		ColumnData::Int1(c) => c.get(i).map(|&v| v as i16).unwrap_or(0),
260		ColumnData::Int2(c) => c.get(i).copied().unwrap_or(0),
261		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i16).unwrap_or(0),
262		_ => 0,
263	}
264}
265
266fn get_as_i32(data: &ColumnData, i: usize) -> i32 {
267	match data {
268		ColumnData::Int1(c) => c.get(i).map(|&v| v as i32).unwrap_or(0),
269		ColumnData::Int2(c) => c.get(i).map(|&v| v as i32).unwrap_or(0),
270		ColumnData::Int4(c) => c.get(i).copied().unwrap_or(0),
271		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i32).unwrap_or(0),
272		ColumnData::Uint2(c) => c.get(i).map(|&v| v as i32).unwrap_or(0),
273		_ => 0,
274	}
275}
276
277fn get_as_i64(data: &ColumnData, i: usize) -> i64 {
278	match data {
279		ColumnData::Int1(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
280		ColumnData::Int2(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
281		ColumnData::Int4(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
282		ColumnData::Int8(c) => c.get(i).copied().unwrap_or(0),
283		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
284		ColumnData::Uint2(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
285		ColumnData::Uint4(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
286		_ => 0,
287	}
288}
289
290fn get_as_i128(data: &ColumnData, i: usize) -> i128 {
291	match data {
292		ColumnData::Int1(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
293		ColumnData::Int2(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
294		ColumnData::Int4(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
295		ColumnData::Int8(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
296		ColumnData::Int16(c) => c.get(i).copied().unwrap_or(0),
297		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
298		ColumnData::Uint2(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
299		ColumnData::Uint4(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
300		ColumnData::Uint8(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
301		_ => 0,
302	}
303}
304
305fn get_as_u16(data: &ColumnData, i: usize) -> u16 {
306	match data {
307		ColumnData::Uint1(c) => c.get(i).map(|&v| v as u16).unwrap_or(0),
308		ColumnData::Uint2(c) => c.get(i).copied().unwrap_or(0),
309		_ => 0,
310	}
311}
312
313fn get_as_u32(data: &ColumnData, i: usize) -> u32 {
314	match data {
315		ColumnData::Uint1(c) => c.get(i).map(|&v| v as u32).unwrap_or(0),
316		ColumnData::Uint2(c) => c.get(i).map(|&v| v as u32).unwrap_or(0),
317		ColumnData::Uint4(c) => c.get(i).copied().unwrap_or(0),
318		_ => 0,
319	}
320}
321
322fn get_as_u64(data: &ColumnData, i: usize) -> u64 {
323	match data {
324		ColumnData::Uint1(c) => c.get(i).map(|&v| v as u64).unwrap_or(0),
325		ColumnData::Uint2(c) => c.get(i).map(|&v| v as u64).unwrap_or(0),
326		ColumnData::Uint4(c) => c.get(i).map(|&v| v as u64).unwrap_or(0),
327		ColumnData::Uint8(c) => c.get(i).copied().unwrap_or(0),
328		_ => 0,
329	}
330}
331
332fn get_as_u128(data: &ColumnData, i: usize) -> u128 {
333	match data {
334		ColumnData::Uint1(c) => c.get(i).map(|&v| v as u128).unwrap_or(0),
335		ColumnData::Uint2(c) => c.get(i).map(|&v| v as u128).unwrap_or(0),
336		ColumnData::Uint4(c) => c.get(i).map(|&v| v as u128).unwrap_or(0),
337		ColumnData::Uint8(c) => c.get(i).map(|&v| v as u128).unwrap_or(0),
338		ColumnData::Uint16(c) => c.get(i).copied().unwrap_or(0),
339		_ => 0,
340	}
341}
342
343fn get_as_f32(data: &ColumnData, i: usize) -> f32 {
344	match data {
345		ColumnData::Int1(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
346		ColumnData::Int2(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
347		ColumnData::Int4(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
348		ColumnData::Int8(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
349		ColumnData::Int16(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
350		ColumnData::Uint1(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
351		ColumnData::Uint2(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
352		ColumnData::Uint4(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
353		ColumnData::Uint8(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
354		ColumnData::Uint16(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
355		ColumnData::Float4(c) => c.get(i).copied().unwrap_or(0.0),
356		ColumnData::Float8(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
357		ColumnData::Int {
358			container,
359			..
360		} => container.get(i).map(|v| v.0.to_f32().unwrap_or(0.0)).unwrap_or(0.0),
361		ColumnData::Uint {
362			container,
363			..
364		} => container.get(i).map(|v| v.0.to_f32().unwrap_or(0.0)).unwrap_or(0.0),
365		ColumnData::Decimal {
366			container,
367			..
368		} => container.get(i).map(|v| v.0.to_f32().unwrap_or(0.0)).unwrap_or(0.0),
369		_ => 0.0,
370	}
371}
372
373fn get_as_f64(data: &ColumnData, i: usize) -> f64 {
374	match data {
375		ColumnData::Int1(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
376		ColumnData::Int2(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
377		ColumnData::Int4(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
378		ColumnData::Int8(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
379		ColumnData::Int16(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
380		ColumnData::Uint1(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
381		ColumnData::Uint2(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
382		ColumnData::Uint4(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
383		ColumnData::Uint8(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
384		ColumnData::Uint16(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
385		ColumnData::Float4(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
386		ColumnData::Float8(c) => c.get(i).copied().unwrap_or(0.0),
387		ColumnData::Int {
388			container,
389			..
390		} => container.get(i).map(|v| v.0.to_f64().unwrap_or(0.0)).unwrap_or(0.0),
391		ColumnData::Uint {
392			container,
393			..
394		} => container.get(i).map(|v| v.0.to_f64().unwrap_or(0.0)).unwrap_or(0.0),
395		ColumnData::Decimal {
396			container,
397			..
398		} => container.get(i).map(|v| v.0.to_f64().unwrap_or(0.0)).unwrap_or(0.0),
399		_ => 0.0,
400	}
401}
402
403fn promote_two(left: Type, right: Type) -> Type {
404	if matches!(left, Type::Float4 | Type::Float8 | Type::Decimal)
405		|| matches!(right, Type::Float4 | Type::Float8 | Type::Decimal)
406	{
407		return Type::Decimal;
408	}
409	if left == Type::Int || right == Type::Int {
410		return Type::Int16;
411	}
412	if left == Type::Uint || right == Type::Uint {
413		if matches!(left, Type::Int1 | Type::Int2 | Type::Int4 | Type::Int8 | Type::Int16)
414			|| matches!(right, Type::Int1 | Type::Int2 | Type::Int4 | Type::Int8 | Type::Int16)
415		{
416			return Type::Int16;
417		}
418		return Type::Uint16;
419	}
420	Type::promote(left, right)
421}
422
423fn promote_numeric_types(a: Type, b: Type, c: Type) -> Type {
424	promote_two(promote_two(a, b), c)
425}
426
427impl ScalarFunction for Clamp {
428	fn scalar(&self, ctx: ScalarFunctionContext) -> ScalarFunctionResult<ColumnData> {
429		if let Some(result) = propagate_options(self, &ctx) {
430			return result;
431		}
432		let columns = ctx.columns;
433		let row_count = ctx.row_count;
434
435		if columns.len() != 3 {
436			return Err(ScalarFunctionError::ArityMismatch {
437				function: ctx.fragment.clone(),
438				expected: 3,
439				actual: columns.len(),
440			});
441		}
442
443		let val_col = columns.get(0).unwrap();
444		let min_col = columns.get(1).unwrap();
445		let max_col = columns.get(2).unwrap();
446
447		match (val_col.data(), min_col.data(), max_col.data()) {
448			(ColumnData::Int1(v), ColumnData::Int1(lo), ColumnData::Int1(hi)) => {
449				let mut result = Vec::with_capacity(row_count);
450				let mut bitvec = Vec::with_capacity(row_count);
451				for i in 0..row_count {
452					match (v.get(i), lo.get(i), hi.get(i)) {
453						(Some(&val), Some(&min), Some(&max)) => {
454							result.push(val.clamp(min, max));
455							bitvec.push(true);
456						}
457						_ => {
458							result.push(0);
459							bitvec.push(false);
460						}
461					}
462				}
463				Ok(ColumnData::int1_with_bitvec(result, bitvec))
464			}
465			(ColumnData::Int2(v), ColumnData::Int2(lo), ColumnData::Int2(hi)) => {
466				let mut result = Vec::with_capacity(row_count);
467				let mut bitvec = Vec::with_capacity(row_count);
468				for i in 0..row_count {
469					match (v.get(i), lo.get(i), hi.get(i)) {
470						(Some(&val), Some(&min), Some(&max)) => {
471							result.push(val.clamp(min, max));
472							bitvec.push(true);
473						}
474						_ => {
475							result.push(0);
476							bitvec.push(false);
477						}
478					}
479				}
480				Ok(ColumnData::int2_with_bitvec(result, bitvec))
481			}
482			(ColumnData::Int4(v), ColumnData::Int4(lo), ColumnData::Int4(hi)) => {
483				let mut result = Vec::with_capacity(row_count);
484				let mut bitvec = Vec::with_capacity(row_count);
485				for i in 0..row_count {
486					match (v.get(i), lo.get(i), hi.get(i)) {
487						(Some(&val), Some(&min), Some(&max)) => {
488							result.push(val.clamp(min, max));
489							bitvec.push(true);
490						}
491						_ => {
492							result.push(0);
493							bitvec.push(false);
494						}
495					}
496				}
497				Ok(ColumnData::int4_with_bitvec(result, bitvec))
498			}
499			(ColumnData::Int8(v), ColumnData::Int8(lo), ColumnData::Int8(hi)) => {
500				let mut result = Vec::with_capacity(row_count);
501				let mut bitvec = Vec::with_capacity(row_count);
502				for i in 0..row_count {
503					match (v.get(i), lo.get(i), hi.get(i)) {
504						(Some(&val), Some(&min), Some(&max)) => {
505							result.push(val.clamp(min, max));
506							bitvec.push(true);
507						}
508						_ => {
509							result.push(0);
510							bitvec.push(false);
511						}
512					}
513				}
514				Ok(ColumnData::int8_with_bitvec(result, bitvec))
515			}
516			(ColumnData::Int16(v), ColumnData::Int16(lo), ColumnData::Int16(hi)) => {
517				let mut result = Vec::with_capacity(row_count);
518				let mut bitvec = Vec::with_capacity(row_count);
519				for i in 0..row_count {
520					match (v.get(i), lo.get(i), hi.get(i)) {
521						(Some(&val), Some(&min), Some(&max)) => {
522							result.push(val.clamp(min, max));
523							bitvec.push(true);
524						}
525						_ => {
526							result.push(0);
527							bitvec.push(false);
528						}
529					}
530				}
531				Ok(ColumnData::int16_with_bitvec(result, bitvec))
532			}
533			(ColumnData::Uint1(v), ColumnData::Uint1(lo), ColumnData::Uint1(hi)) => {
534				let mut result = Vec::with_capacity(row_count);
535				let mut bitvec = Vec::with_capacity(row_count);
536				for i in 0..row_count {
537					match (v.get(i), lo.get(i), hi.get(i)) {
538						(Some(&val), Some(&min), Some(&max)) => {
539							result.push(val.clamp(min, max));
540							bitvec.push(true);
541						}
542						_ => {
543							result.push(0);
544							bitvec.push(false);
545						}
546					}
547				}
548				Ok(ColumnData::uint1_with_bitvec(result, bitvec))
549			}
550			(ColumnData::Uint2(v), ColumnData::Uint2(lo), ColumnData::Uint2(hi)) => {
551				let mut result = Vec::with_capacity(row_count);
552				let mut bitvec = Vec::with_capacity(row_count);
553				for i in 0..row_count {
554					match (v.get(i), lo.get(i), hi.get(i)) {
555						(Some(&val), Some(&min), Some(&max)) => {
556							result.push(val.clamp(min, max));
557							bitvec.push(true);
558						}
559						_ => {
560							result.push(0);
561							bitvec.push(false);
562						}
563					}
564				}
565				Ok(ColumnData::uint2_with_bitvec(result, bitvec))
566			}
567			(ColumnData::Uint4(v), ColumnData::Uint4(lo), ColumnData::Uint4(hi)) => {
568				let mut result = Vec::with_capacity(row_count);
569				let mut bitvec = Vec::with_capacity(row_count);
570				for i in 0..row_count {
571					match (v.get(i), lo.get(i), hi.get(i)) {
572						(Some(&val), Some(&min), Some(&max)) => {
573							result.push(val.clamp(min, max));
574							bitvec.push(true);
575						}
576						_ => {
577							result.push(0);
578							bitvec.push(false);
579						}
580					}
581				}
582				Ok(ColumnData::uint4_with_bitvec(result, bitvec))
583			}
584			(ColumnData::Uint8(v), ColumnData::Uint8(lo), ColumnData::Uint8(hi)) => {
585				let mut result = Vec::with_capacity(row_count);
586				let mut bitvec = Vec::with_capacity(row_count);
587				for i in 0..row_count {
588					match (v.get(i), lo.get(i), hi.get(i)) {
589						(Some(&val), Some(&min), Some(&max)) => {
590							result.push(val.clamp(min, max));
591							bitvec.push(true);
592						}
593						_ => {
594							result.push(0);
595							bitvec.push(false);
596						}
597					}
598				}
599				Ok(ColumnData::uint8_with_bitvec(result, bitvec))
600			}
601			(ColumnData::Uint16(v), ColumnData::Uint16(lo), ColumnData::Uint16(hi)) => {
602				let mut result = Vec::with_capacity(row_count);
603				let mut bitvec = Vec::with_capacity(row_count);
604				for i in 0..row_count {
605					match (v.get(i), lo.get(i), hi.get(i)) {
606						(Some(&val), Some(&min), Some(&max)) => {
607							result.push(val.clamp(min, max));
608							bitvec.push(true);
609						}
610						_ => {
611							result.push(0);
612							bitvec.push(false);
613						}
614					}
615				}
616				Ok(ColumnData::uint16_with_bitvec(result, bitvec))
617			}
618			(ColumnData::Float4(v), ColumnData::Float4(lo), ColumnData::Float4(hi)) => {
619				let mut result = Vec::with_capacity(row_count);
620				let mut bitvec = Vec::with_capacity(row_count);
621				for i in 0..row_count {
622					match (v.get(i), lo.get(i), hi.get(i)) {
623						(Some(&val), Some(&min), Some(&max)) => {
624							result.push(val.clamp(min, max));
625							bitvec.push(true);
626						}
627						_ => {
628							result.push(0.0);
629							bitvec.push(false);
630						}
631					}
632				}
633				Ok(ColumnData::float4_with_bitvec(result, bitvec))
634			}
635			(ColumnData::Float8(v), ColumnData::Float8(lo), ColumnData::Float8(hi)) => {
636				let mut result = Vec::with_capacity(row_count);
637				let mut bitvec = Vec::with_capacity(row_count);
638				for i in 0..row_count {
639					match (v.get(i), lo.get(i), hi.get(i)) {
640						(Some(&val), Some(&min), Some(&max)) => {
641							result.push(val.clamp(min, max));
642							bitvec.push(true);
643						}
644						_ => {
645							result.push(0.0);
646							bitvec.push(false);
647						}
648					}
649				}
650				Ok(ColumnData::float8_with_bitvec(result, bitvec))
651			}
652			(
653				ColumnData::Int {
654					container: v_container,
655					max_bytes,
656				},
657				ColumnData::Int {
658					container: lo_container,
659					..
660				},
661				ColumnData::Int {
662					container: hi_container,
663					..
664				},
665			) => {
666				let mut result = Vec::with_capacity(row_count);
667				let mut bitvec = Vec::with_capacity(row_count);
668				for i in 0..row_count {
669					match (v_container.get(i), lo_container.get(i), hi_container.get(i)) {
670						(Some(val), Some(lo), Some(hi)) => {
671							let v = val.0.to_f64().unwrap_or(0.0);
672							let l = lo.0.to_f64().unwrap_or(0.0);
673							let h = hi.0.to_f64().unwrap_or(0.0);
674							result.push(Int::from(v.clamp(l, h) as i64));
675							bitvec.push(true);
676						}
677						_ => {
678							result.push(Int::default());
679							bitvec.push(false);
680						}
681					}
682				}
683				Ok(ColumnData::Int {
684					container: NumberContainer::new(result),
685					max_bytes: *max_bytes,
686				})
687			}
688			(
689				ColumnData::Uint {
690					container: v_container,
691					max_bytes,
692				},
693				ColumnData::Uint {
694					container: lo_container,
695					..
696				},
697				ColumnData::Uint {
698					container: hi_container,
699					..
700				},
701			) => {
702				let mut result = Vec::with_capacity(row_count);
703				let mut bitvec = Vec::with_capacity(row_count);
704				for i in 0..row_count {
705					match (v_container.get(i), lo_container.get(i), hi_container.get(i)) {
706						(Some(val), Some(lo), Some(hi)) => {
707							let v = val.0.to_f64().unwrap_or(0.0);
708							let l = lo.0.to_f64().unwrap_or(0.0);
709							let h = hi.0.to_f64().unwrap_or(0.0);
710							result.push(Uint::from(v.clamp(l, h) as u64));
711							bitvec.push(true);
712						}
713						_ => {
714							result.push(Uint::default());
715							bitvec.push(false);
716						}
717					}
718				}
719				Ok(ColumnData::Uint {
720					container: NumberContainer::new(result),
721					max_bytes: *max_bytes,
722				})
723			}
724			(
725				ColumnData::Decimal {
726					container: v_container,
727					precision,
728					scale,
729				},
730				ColumnData::Decimal {
731					container: lo_container,
732					..
733				},
734				ColumnData::Decimal {
735					container: hi_container,
736					..
737				},
738			) => {
739				let mut result = Vec::with_capacity(row_count);
740				let mut bitvec = Vec::with_capacity(row_count);
741				for i in 0..row_count {
742					match (v_container.get(i), lo_container.get(i), hi_container.get(i)) {
743						(Some(val), Some(lo), Some(hi)) => {
744							let v = val.0.to_f64().unwrap_or(0.0);
745							let l = lo.0.to_f64().unwrap_or(0.0);
746							let h = hi.0.to_f64().unwrap_or(0.0);
747							result.push(Decimal::from(v.clamp(l, h)));
748							bitvec.push(true);
749						}
750						_ => {
751							result.push(Decimal::default());
752							bitvec.push(false);
753						}
754					}
755				}
756				Ok(ColumnData::Decimal {
757					container: NumberContainer::new(result),
758					precision: *precision,
759					scale: *scale,
760				})
761			}
762			// Mixed-type fallback: validate all 3 are numeric, promote to common type and recurse
763			(v_data, lo_data, hi_data) => {
764				let v_type = v_data.get_type();
765				let lo_type = lo_data.get_type();
766				let hi_type = hi_data.get_type();
767
768				let numeric_types = vec![
769					Type::Int1,
770					Type::Int2,
771					Type::Int4,
772					Type::Int8,
773					Type::Int16,
774					Type::Uint1,
775					Type::Uint2,
776					Type::Uint4,
777					Type::Uint8,
778					Type::Uint16,
779					Type::Float4,
780					Type::Float8,
781					Type::Int,
782					Type::Uint,
783					Type::Decimal,
784				];
785
786				for (idx, t) in [(0, &v_type), (1, &lo_type), (2, &hi_type)] {
787					if !t.is_number() {
788						return Err(ScalarFunctionError::InvalidArgumentType {
789							function: ctx.fragment.clone(),
790							argument_index: idx,
791							expected: numeric_types.clone(),
792							actual: t.clone(),
793						});
794					}
795				}
796
797				let promoted = promote_numeric_types(v_type, lo_type, hi_type);
798				let pv = convert_column_to_type(v_data, promoted.clone(), row_count);
799				let plo = convert_column_to_type(lo_data, promoted.clone(), row_count);
800				let phi = convert_column_to_type(hi_data, promoted, row_count);
801
802				let val_col = Column::new(Fragment::internal("val"), pv);
803				let min_col = Column::new(Fragment::internal("min"), plo);
804				let max_col = Column::new(Fragment::internal("max"), phi);
805				let promoted_columns = Columns::new(vec![val_col, min_col, max_col]);
806
807				let new_ctx = ScalarFunctionContext {
808					fragment: ctx.fragment.clone(),
809					columns: &promoted_columns,
810					row_count,
811					clock: ctx.clock,
812					identity: ctx.identity,
813				};
814				self.scalar(new_ctx)
815			}
816		}
817	}
818
819	fn return_type(&self, input_types: &[Type]) -> Type {
820		if input_types.len() >= 3
821			&& input_types[0].is_number()
822			&& input_types[1].is_number()
823			&& input_types[2].is_number()
824		{
825			promote_numeric_types(input_types[0].clone(), input_types[1].clone(), input_types[2].clone())
826		} else {
827			Type::Float8
828		}
829	}
830}