Search code examples
oraclenumericexecute-immediate

Error numeric overflow oracle when call execute immediate


I define a procedure do parse a formula (type value String) to a value number: Some case value in formula can execute or raise error numeric overflow. Code :

DECLARE
    formula VARCHAR2(1000) := '1111111111 * 2';
    val NUMBER;
BEGIN
    EXECUTE IMMEDIATE 'BEGIN :res := '||formula||'; END;' USING OUT val;
    DBMS_OUTPUT.PUT_LINE ( 'formula = ' || formula );
    DBMS_OUTPUT.PUT_LINE ( 'val = ' || val );
END;

In this case then raise error numeric overflow. When i increase value operands more/less than 10 character 1 then it working right.

I try to check a few values and see most of the error if the value in the formula contains the number 1. Is this the reason?

Thank guys!


Solution

  • When you multiply integers in PL/SQL it's actually using pls_integers.

    There is an upper limit for pls_integer 2,147,483,647 and multiplication used in the example of yours 2,222,222,222 exceeds this and thus result in numeric overflow.

    From the offcial docs and also from ask Tom site:

    A calculation with two PLS_INTEGER values that overflows the PLS_INTEGER range raises an overflow exception, even if you assign the result to a NUMBER data type.

    To get rid of this we can make one of the values in the expression a number.

    Case1: with CAST

    DECLARE
        formula VARCHAR2(1000) := 'cast(1111111111 as number) * 2';
        val NUMBER;
    BEGIN
        EXECUTE IMMEDIATE
        'BEGIN '||
        ' :res := '||formula||';'||
        'END;' USING OUT val;
        DBMS_OUTPUT.PUT_LINE ( 'formula = ' || formula );
        DBMS_OUTPUT.PUT_LINE ( 'val = ' || val );
    END;
    /
    

    Case2: by making one of the expression to decimal and Oracle will implicitly convert it to number

    DECLARE
        formula VARCHAR2(1000) := '1111111111 * 2.0';
        val NUMBER;
    BEGIN
        EXECUTE IMMEDIATE
        'BEGIN '||
        ' :res := '||formula||';'||
        'END;' USING OUT val;
        DBMS_OUTPUT.PUT_LINE ( 'formula = ' || formula );
        DBMS_OUTPUT.PUT_LINE ( 'val = ' || val );
    END;
    /