Skip to main content

reifydb_function/math/scalar/
power.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 Power;
18
19impl Power {
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					let val = get_as_i8(data, i);
33					result.push(val);
34					bitvec.push(true);
35				} else {
36					result.push(0);
37					bitvec.push(false);
38				}
39			}
40			ColumnData::int1_with_bitvec(result, bitvec)
41		}
42		Type::Int2 => {
43			let mut result = Vec::with_capacity(row_count);
44			let mut bitvec = Vec::with_capacity(row_count);
45			for i in 0..row_count {
46				if data.is_defined(i) {
47					let val = get_as_i16(data, i);
48					result.push(val);
49					bitvec.push(true);
50				} else {
51					result.push(0);
52					bitvec.push(false);
53				}
54			}
55			ColumnData::int2_with_bitvec(result, bitvec)
56		}
57		Type::Int4 => {
58			let mut result = Vec::with_capacity(row_count);
59			let mut bitvec = Vec::with_capacity(row_count);
60			for i in 0..row_count {
61				if data.is_defined(i) {
62					let val = get_as_i32(data, i);
63					result.push(val);
64					bitvec.push(true);
65				} else {
66					result.push(0);
67					bitvec.push(false);
68				}
69			}
70			ColumnData::int4_with_bitvec(result, bitvec)
71		}
72		Type::Int8 => {
73			let mut result = Vec::with_capacity(row_count);
74			let mut bitvec = Vec::with_capacity(row_count);
75			for i in 0..row_count {
76				if data.is_defined(i) {
77					let val = get_as_i64(data, i);
78					result.push(val);
79					bitvec.push(true);
80				} else {
81					result.push(0);
82					bitvec.push(false);
83				}
84			}
85			ColumnData::int8_with_bitvec(result, bitvec)
86		}
87		Type::Int16 => {
88			let mut result = Vec::with_capacity(row_count);
89			let mut bitvec = Vec::with_capacity(row_count);
90			for i in 0..row_count {
91				if data.is_defined(i) {
92					let val = get_as_i128(data, i);
93					result.push(val);
94					bitvec.push(true);
95				} else {
96					result.push(0);
97					bitvec.push(false);
98				}
99			}
100			ColumnData::int16_with_bitvec(result, bitvec)
101		}
102		Type::Uint1 => {
103			let mut result = Vec::with_capacity(row_count);
104			let mut bitvec = Vec::with_capacity(row_count);
105			for i in 0..row_count {
106				if data.is_defined(i) {
107					let val = get_as_u8(data, i);
108					result.push(val);
109					bitvec.push(true);
110				} else {
111					result.push(0);
112					bitvec.push(false);
113				}
114			}
115			ColumnData::uint1_with_bitvec(result, bitvec)
116		}
117		Type::Uint2 => {
118			let mut result = Vec::with_capacity(row_count);
119			let mut bitvec = Vec::with_capacity(row_count);
120			for i in 0..row_count {
121				if data.is_defined(i) {
122					let val = get_as_u16(data, i);
123					result.push(val);
124					bitvec.push(true);
125				} else {
126					result.push(0);
127					bitvec.push(false);
128				}
129			}
130			ColumnData::uint2_with_bitvec(result, bitvec)
131		}
132		Type::Uint4 => {
133			let mut result = Vec::with_capacity(row_count);
134			let mut bitvec = Vec::with_capacity(row_count);
135			for i in 0..row_count {
136				if data.is_defined(i) {
137					let val = get_as_u32(data, i);
138					result.push(val);
139					bitvec.push(true);
140				} else {
141					result.push(0);
142					bitvec.push(false);
143				}
144			}
145			ColumnData::uint4_with_bitvec(result, bitvec)
146		}
147		Type::Uint8 => {
148			let mut result = Vec::with_capacity(row_count);
149			let mut bitvec = Vec::with_capacity(row_count);
150			for i in 0..row_count {
151				if data.is_defined(i) {
152					let val = get_as_u64(data, i);
153					result.push(val);
154					bitvec.push(true);
155				} else {
156					result.push(0);
157					bitvec.push(false);
158				}
159			}
160			ColumnData::uint8_with_bitvec(result, bitvec)
161		}
162		Type::Uint16 => {
163			let mut result = Vec::with_capacity(row_count);
164			let mut bitvec = Vec::with_capacity(row_count);
165			for i in 0..row_count {
166				if data.is_defined(i) {
167					let val = get_as_u128(data, i);
168					result.push(val);
169					bitvec.push(true);
170				} else {
171					result.push(0);
172					bitvec.push(false);
173				}
174			}
175			ColumnData::uint16_with_bitvec(result, bitvec)
176		}
177		Type::Float4 => {
178			let mut result = Vec::with_capacity(row_count);
179			let mut bitvec = Vec::with_capacity(row_count);
180			for i in 0..row_count {
181				if data.is_defined(i) {
182					let val = get_as_f32(data, i);
183					result.push(val);
184					bitvec.push(true);
185				} else {
186					result.push(0.0);
187					bitvec.push(false);
188				}
189			}
190			ColumnData::float4_with_bitvec(result, bitvec)
191		}
192		Type::Float8 => {
193			let mut result = Vec::with_capacity(row_count);
194			let mut bitvec = Vec::with_capacity(row_count);
195			for i in 0..row_count {
196				if data.is_defined(i) {
197					let val = get_as_f64(data, i);
198					result.push(val);
199					bitvec.push(true);
200				} else {
201					result.push(0.0);
202					bitvec.push(false);
203				}
204			}
205			ColumnData::float8_with_bitvec(result, bitvec)
206		}
207		Type::Int => {
208			let mut result = Vec::with_capacity(row_count);
209			let mut bitvec = Vec::with_capacity(row_count);
210			for i in 0..row_count {
211				if data.is_defined(i) {
212					let val = get_as_i128(data, i);
213					result.push(Int::from(val));
214					bitvec.push(true);
215				} else {
216					result.push(Int::default());
217					bitvec.push(false);
218				}
219			}
220			ColumnData::int_with_bitvec(result, bitvec)
221		}
222		Type::Uint => {
223			let mut result = Vec::with_capacity(row_count);
224			let mut bitvec = Vec::with_capacity(row_count);
225			for i in 0..row_count {
226				if data.is_defined(i) {
227					let val = get_as_u128(data, i);
228					result.push(Uint::from(val));
229					bitvec.push(true);
230				} else {
231					result.push(Uint::default());
232					bitvec.push(false);
233				}
234			}
235			ColumnData::uint_with_bitvec(result, bitvec)
236		}
237		Type::Decimal => {
238			let mut result = Vec::with_capacity(row_count);
239			let mut bitvec = Vec::with_capacity(row_count);
240			for i in 0..row_count {
241				if data.is_defined(i) {
242					let val = get_as_f64(data, i);
243					result.push(Decimal::from(val));
244					bitvec.push(true);
245				} else {
246					result.push(Decimal::default());
247					bitvec.push(false);
248				}
249			}
250			ColumnData::decimal_with_bitvec(result, bitvec)
251		}
252		// For same type or unsupported conversions, clone the original
253		_ => data.clone(),
254	}
255}
256
257fn get_as_i8(data: &ColumnData, i: usize) -> i8 {
258	match data {
259		ColumnData::Int1(c) => c.get(i).copied().unwrap_or(0),
260		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i8).unwrap_or(0),
261		_ => 0,
262	}
263}
264
265fn get_as_u8(data: &ColumnData, i: usize) -> u8 {
266	match data {
267		ColumnData::Uint1(c) => c.get(i).copied().unwrap_or(0),
268		ColumnData::Int1(c) => c.get(i).map(|&v| v as u8).unwrap_or(0),
269		_ => 0,
270	}
271}
272
273fn get_as_i16(data: &ColumnData, i: usize) -> i16 {
274	match data {
275		ColumnData::Int1(c) => c.get(i).map(|&v| v as i16).unwrap_or(0),
276		ColumnData::Int2(c) => c.get(i).copied().unwrap_or(0),
277		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i16).unwrap_or(0),
278		_ => 0,
279	}
280}
281
282fn get_as_i32(data: &ColumnData, i: usize) -> i32 {
283	match data {
284		ColumnData::Int1(c) => c.get(i).map(|&v| v as i32).unwrap_or(0),
285		ColumnData::Int2(c) => c.get(i).map(|&v| v as i32).unwrap_or(0),
286		ColumnData::Int4(c) => c.get(i).copied().unwrap_or(0),
287		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i32).unwrap_or(0),
288		ColumnData::Uint2(c) => c.get(i).map(|&v| v as i32).unwrap_or(0),
289		_ => 0,
290	}
291}
292
293fn get_as_i64(data: &ColumnData, i: usize) -> i64 {
294	match data {
295		ColumnData::Int1(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
296		ColumnData::Int2(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
297		ColumnData::Int4(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
298		ColumnData::Int8(c) => c.get(i).copied().unwrap_or(0),
299		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
300		ColumnData::Uint2(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
301		ColumnData::Uint4(c) => c.get(i).map(|&v| v as i64).unwrap_or(0),
302		_ => 0,
303	}
304}
305
306fn get_as_i128(data: &ColumnData, i: usize) -> i128 {
307	match data {
308		ColumnData::Int1(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
309		ColumnData::Int2(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
310		ColumnData::Int4(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
311		ColumnData::Int8(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
312		ColumnData::Int16(c) => c.get(i).copied().unwrap_or(0),
313		ColumnData::Uint1(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
314		ColumnData::Uint2(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
315		ColumnData::Uint4(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
316		ColumnData::Uint8(c) => c.get(i).map(|&v| v as i128).unwrap_or(0),
317		_ => 0,
318	}
319}
320
321fn get_as_u16(data: &ColumnData, i: usize) -> u16 {
322	match data {
323		ColumnData::Uint1(c) => c.get(i).map(|&v| v as u16).unwrap_or(0),
324		ColumnData::Uint2(c) => c.get(i).copied().unwrap_or(0),
325		_ => 0,
326	}
327}
328
329fn get_as_u32(data: &ColumnData, i: usize) -> u32 {
330	match data {
331		ColumnData::Uint1(c) => c.get(i).map(|&v| v as u32).unwrap_or(0),
332		ColumnData::Uint2(c) => c.get(i).map(|&v| v as u32).unwrap_or(0),
333		ColumnData::Uint4(c) => c.get(i).copied().unwrap_or(0),
334		_ => 0,
335	}
336}
337
338fn get_as_u64(data: &ColumnData, i: usize) -> u64 {
339	match data {
340		ColumnData::Uint1(c) => c.get(i).map(|&v| v as u64).unwrap_or(0),
341		ColumnData::Uint2(c) => c.get(i).map(|&v| v as u64).unwrap_or(0),
342		ColumnData::Uint4(c) => c.get(i).map(|&v| v as u64).unwrap_or(0),
343		ColumnData::Uint8(c) => c.get(i).copied().unwrap_or(0),
344		_ => 0,
345	}
346}
347
348fn get_as_u128(data: &ColumnData, i: usize) -> u128 {
349	match data {
350		ColumnData::Uint1(c) => c.get(i).map(|&v| v as u128).unwrap_or(0),
351		ColumnData::Uint2(c) => c.get(i).map(|&v| v as u128).unwrap_or(0),
352		ColumnData::Uint4(c) => c.get(i).map(|&v| v as u128).unwrap_or(0),
353		ColumnData::Uint8(c) => c.get(i).map(|&v| v as u128).unwrap_or(0),
354		ColumnData::Uint16(c) => c.get(i).copied().unwrap_or(0),
355		_ => 0,
356	}
357}
358
359fn get_as_f32(data: &ColumnData, i: usize) -> f32 {
360	match data {
361		ColumnData::Int1(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
362		ColumnData::Int2(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
363		ColumnData::Int4(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
364		ColumnData::Int8(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
365		ColumnData::Int16(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
366		ColumnData::Uint1(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
367		ColumnData::Uint2(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
368		ColumnData::Uint4(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
369		ColumnData::Uint8(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
370		ColumnData::Uint16(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
371		ColumnData::Float4(c) => c.get(i).copied().unwrap_or(0.0),
372		ColumnData::Float8(c) => c.get(i).map(|&v| v as f32).unwrap_or(0.0),
373		ColumnData::Int {
374			container,
375			..
376		} => container.get(i).map(|v| v.0.to_f32().unwrap_or(0.0)).unwrap_or(0.0),
377		ColumnData::Uint {
378			container,
379			..
380		} => container.get(i).map(|v| v.0.to_f32().unwrap_or(0.0)).unwrap_or(0.0),
381		ColumnData::Decimal {
382			container,
383			..
384		} => container.get(i).map(|v| v.0.to_f32().unwrap_or(0.0)).unwrap_or(0.0),
385		_ => 0.0,
386	}
387}
388
389fn get_as_f64(data: &ColumnData, i: usize) -> f64 {
390	match data {
391		ColumnData::Int1(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
392		ColumnData::Int2(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
393		ColumnData::Int4(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
394		ColumnData::Int8(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
395		ColumnData::Int16(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
396		ColumnData::Uint1(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
397		ColumnData::Uint2(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
398		ColumnData::Uint4(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
399		ColumnData::Uint8(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
400		ColumnData::Uint16(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
401		ColumnData::Float4(c) => c.get(i).map(|&v| v as f64).unwrap_or(0.0),
402		ColumnData::Float8(c) => c.get(i).copied().unwrap_or(0.0),
403		ColumnData::Int {
404			container,
405			..
406		} => container.get(i).map(|v| v.0.to_f64().unwrap_or(0.0)).unwrap_or(0.0),
407		ColumnData::Uint {
408			container,
409			..
410		} => container.get(i).map(|v| v.0.to_f64().unwrap_or(0.0)).unwrap_or(0.0),
411		ColumnData::Decimal {
412			container,
413			..
414		} => container.get(i).map(|v| v.0.to_f64().unwrap_or(0.0)).unwrap_or(0.0),
415		_ => 0.0,
416	}
417}
418
419/// Promotes two numeric types to a common type for power computation.
420/// This handles types that the standard Type::promote doesn't handle well,
421/// including Int, Uint, and Decimal.
422fn promote_numeric_types(left: Type, right: Type) -> Type {
423	if matches!(left, Type::Float4 | Type::Float8 | Type::Decimal)
424		|| matches!(right, Type::Float4 | Type::Float8 | Type::Decimal)
425	{
426		return Type::Decimal;
427	}
428
429	// If any type is the arbitrary-precision Int or Uint, promote to the largest fixed type
430	// Int -> Int16 (largest signed), Uint -> Uint16 (largest unsigned)
431	// But if mixing signed/unsigned, go to Int16
432	if left == Type::Int || right == Type::Int {
433		return Type::Int16;
434	}
435	if left == Type::Uint || right == Type::Uint {
436		// If the other type is signed, go to Int16
437		if matches!(left, Type::Int1 | Type::Int2 | Type::Int4 | Type::Int8 | Type::Int16)
438			|| matches!(right, Type::Int1 | Type::Int2 | Type::Int4 | Type::Int8 | Type::Int16)
439		{
440			return Type::Int16;
441		}
442		return Type::Uint16;
443	}
444
445	// For standard fixed-size types, use the standard promotion logic
446	Type::promote(left, right)
447}
448
449impl ScalarFunction for Power {
450	fn scalar(&self, ctx: ScalarFunctionContext) -> ScalarFunctionResult<ColumnData> {
451		if let Some(result) = propagate_options(self, &ctx) {
452			return result;
453		}
454		let columns = ctx.columns;
455		let row_count = ctx.row_count;
456
457		// Validate exactly 2 arguments
458		if columns.len() != 2 {
459			return Err(ScalarFunctionError::ArityMismatch {
460				function: ctx.fragment.clone(),
461				expected: 2,
462				actual: columns.len(),
463			});
464		}
465
466		let base_column = columns.get(0).unwrap();
467		let exponent_column = columns.get(1).unwrap();
468
469		match (base_column.data(), exponent_column.data()) {
470			(ColumnData::Int1(base_container), ColumnData::Int1(exp_container)) => {
471				let mut result = Vec::with_capacity(row_count);
472				let mut bitvec = Vec::with_capacity(row_count);
473
474				for row_idx in 0..row_count {
475					let base = base_container.get(row_idx);
476					let exp = exp_container.get(row_idx);
477
478					match (base, exp) {
479						(Some(&base_val), Some(&exp_val)) => {
480							let power_result = if exp_val < 0 {
481								0 // Integer power with negative exponent results in 0
482							} else {
483								(base_val as i32).pow(exp_val as u32)
484							};
485							result.push(power_result);
486							bitvec.push(true);
487						}
488						_ => {
489							result.push(0);
490							bitvec.push(false);
491						}
492					}
493				}
494
495				Ok(ColumnData::int4_with_bitvec(result, bitvec))
496			}
497			(ColumnData::Int2(base_container), ColumnData::Int2(exp_container)) => {
498				let mut result = Vec::with_capacity(row_count);
499				let mut bitvec = Vec::with_capacity(row_count);
500
501				for row_idx in 0..row_count {
502					let base = base_container.get(row_idx);
503					let exp = exp_container.get(row_idx);
504
505					match (base, exp) {
506						(Some(&base_val), Some(&exp_val)) => {
507							let power_result = if exp_val < 0 {
508								0
509							} else {
510								(base_val as i32).pow(exp_val as u32)
511							};
512							result.push(power_result);
513							bitvec.push(true);
514						}
515						_ => {
516							result.push(0);
517							bitvec.push(false);
518						}
519					}
520				}
521
522				Ok(ColumnData::int4_with_bitvec(result, bitvec))
523			}
524			(ColumnData::Int4(base_container), ColumnData::Int4(exp_container)) => {
525				let mut result = Vec::with_capacity(row_count);
526				let mut bitvec = Vec::with_capacity(row_count);
527
528				for row_idx in 0..row_count {
529					let base = base_container.get(row_idx);
530					let exp = exp_container.get(row_idx);
531
532					match (base, exp) {
533						(Some(&base_val), Some(&exp_val)) => {
534							let power_result = if exp_val < 0 {
535								0
536							} else {
537								base_val.saturating_pow(exp_val as u32)
538							};
539							result.push(power_result);
540							bitvec.push(true);
541						}
542						_ => {
543							result.push(0);
544							bitvec.push(false);
545						}
546					}
547				}
548
549				Ok(ColumnData::int4_with_bitvec(result, bitvec))
550			}
551			(ColumnData::Int8(base_container), ColumnData::Int8(exp_container)) => {
552				let mut result = Vec::with_capacity(row_count);
553				let mut bitvec = Vec::with_capacity(row_count);
554
555				for row_idx in 0..row_count {
556					let base = base_container.get(row_idx);
557					let exp = exp_container.get(row_idx);
558
559					match (base, exp) {
560						(Some(&base_val), Some(&exp_val)) => {
561							let power_result = if exp_val < 0 {
562								0
563							} else {
564								base_val.saturating_pow(exp_val as u32)
565							};
566							result.push(power_result);
567							bitvec.push(true);
568						}
569						_ => {
570							result.push(0);
571							bitvec.push(false);
572						}
573					}
574				}
575
576				Ok(ColumnData::int8_with_bitvec(result, bitvec))
577			}
578			(ColumnData::Int16(base_container), ColumnData::Int16(exp_container)) => {
579				let mut result = Vec::with_capacity(row_count);
580				let mut bitvec = Vec::with_capacity(row_count);
581
582				for row_idx in 0..row_count {
583					let base = base_container.get(row_idx);
584					let exp = exp_container.get(row_idx);
585
586					match (base, exp) {
587						(Some(&base_val), Some(&exp_val)) => {
588							let power_result = if exp_val < 0 {
589								0
590							} else {
591								base_val.saturating_pow(exp_val as u32)
592							};
593							result.push(power_result);
594							bitvec.push(true);
595						}
596						_ => {
597							result.push(0);
598							bitvec.push(false);
599						}
600					}
601				}
602
603				Ok(ColumnData::int16_with_bitvec(result, bitvec))
604			}
605			(ColumnData::Uint1(base_container), ColumnData::Uint1(exp_container)) => {
606				let mut result = Vec::with_capacity(row_count);
607				let mut bitvec = Vec::with_capacity(row_count);
608
609				for row_idx in 0..row_count {
610					let base = base_container.get(row_idx);
611					let exp = exp_container.get(row_idx);
612
613					match (base, exp) {
614						(Some(&base_val), Some(&exp_val)) => {
615							let power_result =
616								(base_val as u32).saturating_pow(exp_val as u32);
617							result.push(power_result);
618							bitvec.push(true);
619						}
620						_ => {
621							result.push(0);
622							bitvec.push(false);
623						}
624					}
625				}
626
627				Ok(ColumnData::uint4_with_bitvec(result, bitvec))
628			}
629			(ColumnData::Uint2(base_container), ColumnData::Uint2(exp_container)) => {
630				let mut result = Vec::with_capacity(row_count);
631				let mut bitvec = Vec::with_capacity(row_count);
632
633				for row_idx in 0..row_count {
634					let base = base_container.get(row_idx);
635					let exp = exp_container.get(row_idx);
636
637					match (base, exp) {
638						(Some(&base_val), Some(&exp_val)) => {
639							let power_result =
640								(base_val as u32).saturating_pow(exp_val as u32);
641							result.push(power_result);
642							bitvec.push(true);
643						}
644						_ => {
645							result.push(0);
646							bitvec.push(false);
647						}
648					}
649				}
650
651				Ok(ColumnData::uint4_with_bitvec(result, bitvec))
652			}
653			(ColumnData::Uint4(base_container), ColumnData::Uint4(exp_container)) => {
654				let mut result = Vec::with_capacity(row_count);
655				let mut bitvec = Vec::with_capacity(row_count);
656
657				for row_idx in 0..row_count {
658					let base = base_container.get(row_idx);
659					let exp = exp_container.get(row_idx);
660
661					match (base, exp) {
662						(Some(&base_val), Some(&exp_val)) => {
663							let power_result = base_val.saturating_pow(exp_val);
664							result.push(power_result);
665							bitvec.push(true);
666						}
667						_ => {
668							result.push(0);
669							bitvec.push(false);
670						}
671					}
672				}
673
674				Ok(ColumnData::uint4_with_bitvec(result, bitvec))
675			}
676			(ColumnData::Uint8(base_container), ColumnData::Uint8(exp_container)) => {
677				let mut result = Vec::with_capacity(row_count);
678				let mut bitvec = Vec::with_capacity(row_count);
679
680				for row_idx in 0..row_count {
681					let base = base_container.get(row_idx);
682					let exp = exp_container.get(row_idx);
683
684					match (base, exp) {
685						(Some(&base_val), Some(&exp_val)) => {
686							let power_result = base_val.saturating_pow(exp_val as u32);
687							result.push(power_result);
688							bitvec.push(true);
689						}
690						_ => {
691							result.push(0);
692							bitvec.push(false);
693						}
694					}
695				}
696
697				Ok(ColumnData::uint8_with_bitvec(result, bitvec))
698			}
699			(ColumnData::Uint16(base_container), ColumnData::Uint16(exp_container)) => {
700				let mut result = Vec::with_capacity(row_count);
701				let mut bitvec = Vec::with_capacity(row_count);
702
703				for row_idx in 0..row_count {
704					let base = base_container.get(row_idx);
705					let exp = exp_container.get(row_idx);
706
707					match (base, exp) {
708						(Some(&base_val), Some(&exp_val)) => {
709							let power_result = base_val.saturating_pow(exp_val as u32);
710							result.push(power_result);
711							bitvec.push(true);
712						}
713						_ => {
714							result.push(0);
715							bitvec.push(false);
716						}
717					}
718				}
719
720				Ok(ColumnData::uint16_with_bitvec(result, bitvec))
721			}
722			(ColumnData::Float4(base_container), ColumnData::Float4(exp_container)) => {
723				let mut result = Vec::with_capacity(row_count);
724				let mut bitvec = Vec::with_capacity(row_count);
725
726				for row_idx in 0..row_count {
727					let base = base_container.get(row_idx);
728					let exp = exp_container.get(row_idx);
729
730					match (base, exp) {
731						(Some(&base_val), Some(&exp_val)) => {
732							result.push(base_val.powf(exp_val));
733							bitvec.push(true);
734						}
735						_ => {
736							result.push(0.0);
737							bitvec.push(false);
738						}
739					}
740				}
741
742				Ok(ColumnData::float4_with_bitvec(result, bitvec))
743			}
744			(ColumnData::Float8(base_container), ColumnData::Float8(exp_container)) => {
745				let mut result = Vec::with_capacity(row_count);
746				let mut bitvec = Vec::with_capacity(row_count);
747
748				for row_idx in 0..row_count {
749					let base = base_container.get(row_idx);
750					let exp = exp_container.get(row_idx);
751
752					match (base, exp) {
753						(Some(&base_val), Some(&exp_val)) => {
754							result.push(base_val.powf(exp_val));
755							bitvec.push(true);
756						}
757						_ => {
758							result.push(0.0);
759							bitvec.push(false);
760						}
761					}
762				}
763
764				Ok(ColumnData::float8_with_bitvec(result, bitvec))
765			}
766			(
767				ColumnData::Int {
768					container: base_container,
769					max_bytes,
770				},
771				ColumnData::Int {
772					container: exp_container,
773					..
774				},
775			) => {
776				let mut result = Vec::with_capacity(row_count);
777				let mut bitvec = Vec::with_capacity(row_count);
778
779				for row_idx in 0..row_count {
780					let base = base_container.get(row_idx);
781					let exp = exp_container.get(row_idx);
782
783					match (base, exp) {
784						(Some(base_val), Some(exp_val)) => {
785							let b = base_val.0.to_f64().unwrap_or(0.0);
786							let e = exp_val.0.to_f64().unwrap_or(0.0);
787							result.push(Int::from(b.powf(e) as i64));
788							bitvec.push(true);
789						}
790						_ => {
791							result.push(Int::default());
792							bitvec.push(false);
793						}
794					}
795				}
796
797				Ok(ColumnData::Int {
798					container: NumberContainer::new(result),
799					max_bytes: *max_bytes,
800				})
801			}
802			(
803				ColumnData::Uint {
804					container: base_container,
805					max_bytes,
806				},
807				ColumnData::Uint {
808					container: exp_container,
809					..
810				},
811			) => {
812				let mut result = Vec::with_capacity(row_count);
813				let mut bitvec = Vec::with_capacity(row_count);
814
815				for row_idx in 0..row_count {
816					let base = base_container.get(row_idx);
817					let exp = exp_container.get(row_idx);
818
819					match (base, exp) {
820						(Some(base_val), Some(exp_val)) => {
821							let b = base_val.0.to_f64().unwrap_or(0.0);
822							let e = exp_val.0.to_f64().unwrap_or(0.0);
823							result.push(Uint::from(b.powf(e) as u64));
824							bitvec.push(true);
825						}
826						_ => {
827							result.push(Uint::default());
828							bitvec.push(false);
829						}
830					}
831				}
832
833				Ok(ColumnData::Uint {
834					container: NumberContainer::new(result),
835					max_bytes: *max_bytes,
836				})
837			}
838			(
839				ColumnData::Decimal {
840					container: base_container,
841					precision,
842					scale,
843				},
844				ColumnData::Decimal {
845					container: exp_container,
846					..
847				},
848			) => {
849				let mut result = Vec::with_capacity(row_count);
850				let mut bitvec = Vec::with_capacity(row_count);
851
852				for row_idx in 0..row_count {
853					let base = base_container.get(row_idx);
854					let exp = exp_container.get(row_idx);
855
856					match (base, exp) {
857						(Some(base_val), Some(exp_val)) => {
858							let b = base_val.0.to_f64().unwrap_or(0.0);
859							let e = exp_val.0.to_f64().unwrap_or(0.0);
860
861							result.push(Decimal::from(b.powf(e)));
862							bitvec.push(true);
863						}
864						_ => {
865							result.push(Decimal::default());
866							bitvec.push(false);
867						}
868					}
869				}
870
871				Ok(ColumnData::Decimal {
872					container: NumberContainer::new(result),
873					precision: *precision,
874					scale: *scale,
875				})
876			}
877			// Mixed-type case: promote both columns to a common type and recurse
878			(base_data, exp_data) => {
879				let base_type = base_data.get_type();
880				let exp_type = exp_data.get_type();
881
882				if !base_type.is_number() || !exp_type.is_number() {
883					return Err(ScalarFunctionError::InvalidArgumentType {
884						function: ctx.fragment.clone(),
885						argument_index: 0,
886						expected: vec![
887							Type::Int1,
888							Type::Int2,
889							Type::Int4,
890							Type::Int8,
891							Type::Int16,
892							Type::Uint1,
893							Type::Uint2,
894							Type::Uint4,
895							Type::Uint8,
896							Type::Uint16,
897							Type::Float4,
898							Type::Float8,
899							Type::Int,
900							Type::Uint,
901							Type::Decimal,
902						],
903						actual: base_type,
904					});
905				}
906
907				let promoted_type = promote_numeric_types(base_type, exp_type);
908
909				let promoted_base = convert_column_to_type(base_data, promoted_type.clone(), row_count);
910				let promoted_exp = convert_column_to_type(exp_data, promoted_type, row_count);
911
912				let base_col = Column::new(Fragment::internal("base"), promoted_base);
913				let exp_col = Column::new(Fragment::internal("exp"), promoted_exp);
914				let promoted_columns = Columns::new(vec![base_col, exp_col]);
915
916				let new_ctx = ScalarFunctionContext {
917					fragment: ctx.fragment.clone(),
918					columns: &promoted_columns,
919					row_count,
920					clock: ctx.clock,
921					identity: ctx.identity,
922				};
923				self.scalar(new_ctx)
924			}
925		}
926	}
927
928	fn return_type(&self, input_types: &[Type]) -> Type {
929		promote_numeric_types(input_types[0].clone(), input_types[1].clone())
930	}
931}