2

I have a function defined by

CREATE OR REPLACE FUNCTION public.div(dividend INTEGER, divisor INTEGER)
    RETURNS INTEGER
    LANGUAGE 'sql'
    IMMUTABLE
    LEAKPROOF
    STRICT
    SECURITY DEFINER
    PARALLEL SAFE
    AS $BODY$
        SELECT ($1 + $2/2) / $2;
    $BODY$;

It should calculate a commercial rounded result. Most of the times, it does the job. I don't know why, but select div(5, 3) gives me the correct answer while it doesn't when one parameter is calculated by an aggregate, e.g. select div(sum(val), 3) from (select 1 as val UNION SELECT 4) list is sufficient to trigger that. How can I fix div? I don't want to cast every input.

BTW, using SELECT (cast($1 as integer) + cast($2 as integer)/2) / cast($2 as integer); as the definition of div didn't help.

2 Answers 2

2

Allow floats as parameters, then explicitly cast at the calculation, otherwise you have an implied conversion whilst passing the parameter.

CREATE OR REPLACE FUNCTION my_div(dividend FLOAT, divisor FLOAT)
    RETURNS INTEGER
    LANGUAGE 'sql'
    IMMUTABLE
    -- LEAKPROOF -- not allowed at dbfiddle.uk
    STRICT
    SECURITY DEFINER
    PARALLEL SAFE
    AS $BODY$
        SELECT --($1 + $2/2) / $2;
           (cast($1 as integer) + cast($2 as integer)/2) / cast($2 as integer)
    $BODY$;
select my_div(sum(val), 3) 
from (select 1 as val UNION SELECT 4) x
| my_div |
| -----: |
|      2 |

dbfiddle here

Sign up to request clarification or add additional context in comments.

Comments

2

Change the name of the function.

The function div(numeric, numeric) is a builtin Postgres function and there is an ambiguity which function you want to call:

select div(5, 3)           -- calls your function public.div(integer, integer)
select div(5::bigint, 3)   -- calls pg_catalog.div(numeric, numeric)

In the second case the arguments have to be resolved and the system function is chosen as first.

Note that the function sum(integer) gives bigint as a result.

1 Comment

So awful I didn't think about that. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.