DROP FUNCTION without knowing the number/type of parameters?

后端 未结 7 857
面向向阳花
面向向阳花 2020-12-01 02:20

I keep all my functions in a text file with \'CREATE OR REPLACE FUNCTION somefunction\'. So if I add or change some function I just feed the file to psql.

7条回答
  •  無奈伤痛
    2020-12-01 02:23

    Basic query

    This query creates all necessary DDL statements. Later simplified with a cast to regprocedure, which displays as function with argument types, schema-qualified and/or double-quoted where necessary. Exactly what we need:

    SELECT 'DROP FUNCTION ' || oid::regprocedure
    FROM   pg_proc
    WHERE  proname = 'my_function_name'  -- name without schema-qualification
    AND    pg_function_is_visible(oid);  -- restrict to current search_path ..
                                         -- .. you may or may not want this
    

    Output:

    DROP FUNCTION my_function_name(string text, form text, maxlen integer);
    DROP FUNCTION my_function_name(string text, form text);
    DROP FUNCTION my_function_name(string text);
    

    Execute the commands (after a plausibility check).

    The function name is case-sensitive and with no added double-quotes when passed as text parameter to match against pg_proc.proname.

    The cast to the object identifier type regprocedure (oid::regprocedure) makes all identifiers safe against SQL injection (by way of maliciously malformed identifiers). When converting to text, the function name is double-quoted and schema-qualified according to the current search_path automatically where needed.

    pg_function_is_visible(oid) restricts the selection to functions in the current search_path. You may or may not want that. With the condition pg_function_is_visible(oid) in place, the function is guaranteed to be visible.

    If you have multiple functions of the same name in multiple schemas, or overloaded functions with various function arguments, all of those will be listed separately. You may want to restrict to specific schema(s) or specific function parameter(s) after all.

    Related:

    • When / how are default value expression functions bound with regard to search_path?

    Function

    You can build a plpgsql function around this to execute the statements immediately with EXECUTE. For Postgres 9.1 or later: Careful! It drops your functions!

    CREATE OR REPLACE FUNCTION f_delfunc(_name text, OUT func_dropped int) AS
    $func$
    DECLARE
       _sql text;
    BEGIN
       SELECT count(*)::int
            , 'DROP FUNCTION ' || string_agg(oid::regprocedure::text, '; DROP FUNCTION ')
       FROM   pg_proc
       WHERE  proname = _name
       AND    pg_function_is_visible(oid)
       INTO   func_dropped, _sql;  -- only returned if trailing DROPs succeed
    
       IF func_dropped > 0 THEN    -- only if function(s) found
         EXECUTE _sql;
       END IF;
    END
    $func$ LANGUAGE plpgsql;
    

    Call:

    SELECT * FROM f_delfunc('my_function_name');
    

    Or just:

    SELECT f_delfunc('my_function_name');
    

    This way you don't get the column name func_dropped for the result column. May not matter.

    The function returns the number of functions found and dropped (no exception raised) - 0 if none were found.

    It assumes a (default) search_path where pg_catalog has not been moved around. See:

    • How does the search_path influence identifier resolution and the "current schema"
    • Truncating all tables in a Postgres database
    • PostgreSQL parameterized Order By / Limit in table function

    For Postgres versions older than 9.1 or older variants of the function using regproc and pg_get_function_identity_arguments(oid) check the edit history of this answer.

提交回复
热议问题