Search code examples
postgresqlpostgresql-9.3

Equivalent or alternative method for RAISE EXCEPTION statement for function in LANGUAGE sql?


Is there an equivalent (or workaround) for the RAISE EXCEPTION statement for the function written below in LANGUAGE sql?

CREATE OR REPLACE FUNCTION fn_interpolation (p_yearinteger integer, 
p_admin_id integer, p_crop_id integer, p_cropparameter integer)

RETURNS TABLE (value double precision, remark text)

AS $$

WITH

yearvalues AS (SELECT yearinteger, value FROM cropvalues WHERE crops_id = 
p_crop_id AND admin_id = p_admin_id AND parameter_id = p_cropparameter),

I need the function to abort and to RETURN an error message if the arguments entered into the function do not exist. e.g. IF parameter_id != p_cropparameter THEN RAISE EXCEPTION ‘invalid cropparameter’ END IF


Solution

  • Just define a trivial wrapper function.

    CREATE OR REPLACE FUNCTION raise_exception(text) RETURNS text AS $$
    BEGIN
        RAISE EXCEPTION '%',$1;
    END;
    $$ LANGUAGE plpgsql VOLATILE;
    

    then use CASE:

    SELECT CASE 
             WHEN parameter_id != p_cropparameter 
               THEN raise_exception("blah") 
             ELSE parameter_id 
           END;
    

    This only works if the CASE otherwise returns text though, e.g. if parameter_id is integer you get:

    regress=> SELECT CASE WHEN 1 = 2 THEN raise_exception('blah') ELSE 1 END;
    ERROR:  CASE types integer and text cannot be matched
    LINE 1: SELECT CASE WHEN 1 = 2 THEN raise_exception('blah') ELSE 1 E...
    

    You can work around this with a hack using polymorphic functions. Define:

    CREATE OR REPLACE FUNCTION raise_exception(anyelement, text) RETURNS anyelement AS $$
    BEGIN
        RAISE EXCEPTION '%',$2;
        RETURN $1;
    END;
    $$ LANGUAGE plpgsql VOLATILE;
    

    then pass a fake value of the case type to it so PostgreSQL type-matches it correctly, e.g.

    SELECT CASE WHEN 1 = 1 THEN raise_exception(0, 'blah') ELSE 1 END;
    

    or

    SELECT CASE WHEN 1 = 1 THEN raise_exception(NULL::integer, 'blah') ELSE 1 END;
    

    All seem too hard? That's because really, this sort of thing is usually just better done in PL/PgSQL.