Skip to content

Commit 3bee295

Browse files
authored
fix(query): reject negative factorial inputs (#19891)
1 parent 102392d commit 3bee295

4 files changed

Lines changed: 42 additions & 3 deletions

File tree

src/query/functions/src/scalars/mathematics/src/math.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,20 @@ pub fn register(registry: &mut FunctionRegistry) {
452452
|_, _| FunctionDomain::MayThrow,
453453
vectorize_with_builder_1_arg::<NumberType<NUM_TYPE>, NumberType<i64>>(
454454
|val, output, ctx| {
455-
let n: i64 = AsPrimitive::<i64>::as_(val);
456-
if n > MAX_FACTORIAL_NUMBER {
455+
let max = AsPrimitive::<NUM_TYPE>::as_(MAX_FACTORIAL_NUMBER);
456+
if val > max {
457457
ctx.set_error(output.len(), format!("factorial number is out of range, max is: {}", MAX_FACTORIAL_NUMBER));
458458
output.push(0);
459+
return;
460+
}
461+
462+
let n = AsPrimitive::<i64>::as_(val);
463+
if n < 0 {
464+
ctx.set_error(
465+
output.len(),
466+
"factorial number is out of range, min is: 0".to_string(),
467+
);
468+
output.push(0);
459469
} else {
460470
output.push(factorial(n));
461471
}
@@ -567,5 +577,5 @@ type Log10Function = GenericLogFunction<TenBase>;
567577
type Log2Function = GenericLogFunction<TwoBase>;
568578

569579
fn factorial(n: i64) -> i64 {
570-
if n <= 0 { 1 } else { n * factorial(n - 1) }
580+
if n == 0 { 1 } else { n * factorial(n - 1) }
571581
}

src/query/functions/tests/it/scalars/math.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,12 @@ fn test_cbrt(file: &mut impl Write) {
141141

142142
fn test_factorial(file: &mut impl Write) {
143143
run_ast(file, "factorial(5)", &[]);
144+
run_ast(file, "factorial(-1)", &[]);
144145
run_ast(file, "factorial(30)", &[]);
146+
run_ast(file, "factorial(u)", &[(
147+
"u",
148+
UInt64Type::from_data(vec![u64::MAX]),
149+
)]);
145150
run_ast(file, "factorial(a)", &[(
146151
"a",
147152
Int64Type::from_data(vec![3, 12, 16]),

src/query/functions/tests/it/scalars/testdata/math.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,14 @@ output domain : {120..=120}
636636
output : 120
637637

638638

639+
error:
640+
--> SQL:1:1
641+
|
642+
1 | factorial(-1)
643+
| ^^^^^^^^^^^^^ factorial number is out of range, min is: 0 while evaluating function `factorial(-1)` in expr `factorial(-1)`
644+
645+
646+
639647
error:
640648
--> SQL:1:1
641649
|
@@ -644,6 +652,14 @@ error:
644652

645653

646654

655+
error:
656+
--> SQL:1:1
657+
|
658+
1 | factorial(u)
659+
| ^^^^^^^^^^^^ factorial number is out of range, max is: 20 while evaluating function `factorial(18446744073709551615)` in expr `factorial(u)`
660+
661+
662+
647663
ast : factorial(a)
648664
raw expr : factorial(a::Int64)
649665
checked expr : factorial<Int64>(a)

tests/sqllogictests/suites/query/functions/02_0014_function_maths.test

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,18 @@ SELECT factorial(5)
329329
----
330330
120
331331

332+
statement error 1006
333+
SELECT factorial(-1)
334+
335+
332336
statement error 1006
333337
SELECT factorial(30)
334338

335339

340+
statement error 1006
341+
SELECT factorial(18446744073709551615::UInt64)
342+
343+
336344
statement error 1006
337345
SELECT pow('a', 2)
338346

0 commit comments

Comments
 (0)