diff --git a/pkg/sql/plan/function/func_binary.go b/pkg/sql/plan/function/func_binary.go index 960a6aa488789..5a44ef429c19f 100644 --- a/pkg/sql/plan/function/func_binary.go +++ b/pkg/sql/plan/function/func_binary.go @@ -6722,6 +6722,13 @@ func Power(ivecs []*vector.Vector, result vector.FunctionResultWrapper, _ *proce rs := vector.MustFunctionResult[float64](result) for i := uint64(0); i < uint64(length); i++ { + if selectList != nil && (selectList.IgnoreAllRow() || + (!selectList.ShouldEvalAllRow() && selectList.Contains(i))) { + if err = rs.Append(0, true); err != nil { + return err + } + continue + } v1, null1 := p1.GetValue(i) v2, null2 := p2.GetValue(i) if null1 || null2 { @@ -6729,8 +6736,11 @@ func Power(ivecs []*vector.Vector, result vector.FunctionResultWrapper, _ *proce return err } } else { - //TODO: Ignoring 4 switch cases:https://github.com/m-schen/matrixone/blob/0c480ca11b6302de26789f916a3e2faca7f79d47/pkg/sql/plan/function/builtin/binary/power.go#L36 res := math.Pow(v1, v2) + if math.IsNaN(res) || math.IsInf(res, 0) { + return moerr.NewOutOfRangeNoCtxf( + "float64", "DOUBLE value is out of range in 'pow(%v,%v)'", v1, v2) + } if err = rs.Append(res, false); err != nil { return err } diff --git a/pkg/sql/plan/function/func_binary_test.go b/pkg/sql/plan/function/func_binary_test.go index 1b14388493131..4f3d19ac11aed 100644 --- a/pkg/sql/plan/function/func_binary_test.go +++ b/pkg/sql/plan/function/func_binary_test.go @@ -5033,6 +5033,68 @@ func TestPower(t *testing.T) { } } +func TestPowerOutOfRange(t *testing.T) { + testCases := []struct { + name string + bases []float64 + exponents []float64 + }{ + {name: "negative base with fractional exponent", bases: []float64{-2}, exponents: []float64{0.5}}, + {name: "zero base with negative exponent", bases: []float64{0}, exponents: []float64{-1}}, + {name: "invalid value after valid value", bases: []float64{2, -2}, exponents: []float64{3, 0.5}}, + } + + proc := testutil.NewProcess(t) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tcc := NewFunctionTestCase( + proc, + []FunctionTestInput{ + NewFunctionTestInput(types.T_float64.ToType(), tc.bases, nil), + NewFunctionTestInput(types.T_float64.ToType(), tc.exponents, nil), + }, + NewFunctionTestResult(types.T_float64.ToType(), true, []float64{0}, nil), + Power, + ) + + require.NoError(t, tcc.result.PreExtendAndReset(tcc.fnLength)) + _, err := tcc.DebugRun() + require.Error(t, err) + require.True(t, moerr.IsMoErrCode(err, moerr.ErrOutOfRange)) + require.ErrorContains(t, err, "DOUBLE value is out of range") + }) + } +} + +func TestPowerRespectsSelectList(t *testing.T) { + proc := testutil.NewProcess(t) + inputs := []FunctionTestInput{ + NewFunctionTestInput(types.T_float64.ToType(), []float64{-2, 2}, nil), + NewFunctionTestInput(types.T_float64.ToType(), []float64{0.5, 3}, nil), + } + tcc := NewFunctionTestCase( + proc, + inputs, + NewFunctionTestResult(types.T_float64.ToType(), false, []float64{0, 8}, []bool{true, false}), + Power, + ) + require.NoError(t, tcc.result.PreExtendAndReset(tcc.fnLength)) + + selectList := &FunctionSelectList{ + AnyNull: true, + SelectList: []bool{false, true}, + } + err := Power(tcc.parameters, tcc.result, proc, tcc.fnLength, selectList) + require.NoError(t, err) + + resultVec := tcc.result.GetResultVector() + require.True(t, resultVec.GetNulls().Contains(0)) + resultParam := vector.GenerateFunctionFixedTypeParameter[float64](resultVec) + value, isNull := resultParam.GetValue(1) + require.False(t, isNull) + require.Equal(t, float64(8), value) +} + // TRUNCATE func initTruncateTestCase() []tcTemp { cases := []struct { diff --git a/test/distributed/cases/function/func_math_power.result b/test/distributed/cases/function/func_math_power.result index a2d53f162a3fd..d2d5446617829 100644 --- a/test/distributed/cases/function/func_math_power.result +++ b/test/distributed/cases/function/func_math_power.result @@ -19,6 +19,16 @@ result5 SELECT POWER(4, 0.5) AS result6; result6 2.0 +SELECT POW(-2, 0.5); +Data truncation: data out of range: data type float64, DOUBLE value is out of range in 'pow(-2,0.5)' +SELECT POWER(0, -1); +Data truncation: data out of range: data type float64, DOUBLE value is out of range in 'pow(0,-1)' +SELECT IF(0, POW(-2, 0.5), 1); +IF(0, POW(-2, 0.5), 1) +1.0 +SELECT CASE WHEN 0 THEN POWER(0, -1) ELSE 1 END; +case when 0 then POWER(0, -1) else 1 end +1.0 SELECT POW(2, 3) = POWER(2, 3) AS same_result; same_result 1 diff --git a/test/distributed/cases/function/func_math_power.test b/test/distributed/cases/function/func_math_power.test index 24b51a69d6776..95859c5a57ea4 100644 --- a/test/distributed/cases/function/func_math_power.test +++ b/test/distributed/cases/function/func_math_power.test @@ -9,6 +9,12 @@ SELECT POWER(2, 3) AS result4; SELECT POWER(2, 0) AS result5; SELECT POWER(4, 0.5) AS result6; +#SELECT - Out-of-range results +SELECT POW(-2, 0.5); +SELECT POWER(0, -1); +SELECT IF(0, POW(-2, 0.5), 1); +SELECT CASE WHEN 0 THEN POWER(0, -1) ELSE 1 END; + #SELECT - Verify POW and POWER are aliases SELECT POW(2, 3) = POWER(2, 3) AS same_result; @@ -75,4 +81,3 @@ create table t1(a float, b float); insert into t1 values(14.3, 4.413), (9.123, 9.409); select b from t1 group by b having power(1,b)>0; drop table t1; -