Search code examples
sqlpostgresql

Is it possible to create a procedure with ANALYZE table instruction?


I have to call procedure to analyze table by name. example: call schema_name.analyze('table_name'). I've created procedure, but I'm gettin an error

ERROR: relation "x" does not exist.

How to deal with it?

CREATE OR REPLACE PROCEDURE schema_name.analyze(IN x VARCHAR)
LANGUAGE plpgsql
AS $$
begin
    analyze x;
END;
$$;

Solution

  • What worked for me:

    CREATE OR REPLACE PROCEDURE public.analyze_test(x character varying)
     LANGUAGE plpgsql
    AS $procedure$
    begin
        EXECUTE 'analyze ' || quote_ident(x);
    END;
    $procedure$
    

    Since you are doing dynamic naming use EXECUTE. Then quote_ident() to get the passed in name correctly quoted.

    UPDATE

    Example of why quote_ident() is important:

    create table "MixedCase" (id int);
    
    CREATE OR REPLACE PROCEDURE public.analyze_test(x character varying)
     LANGUAGE plpgsql
    AS $procedure$
    begin
        EXECUTE 'analyze ' || x;
    END;
    $procedure$
    
    call analyze_test('MixedCase');
    ERROR:  relation "mixedcase" does not exist
    CONTEXT:  SQL statement "analyze MixedCase"
    PL/pgSQL function analyze_test(character varying) line 3 at EXECUTE
    
    CREATE OR REPLACE PROCEDURE public.analyze_test(x character varying)
     LANGUAGE plpgsql
    AS $procedure$
    begin
        EXECUTE 'analyze ' || quote_ident(x);
    END;
    $procedure$
    
    call analyze_test('MixedCase');
    CALL
    
    

    UPDATE 2

    To have a procedure or function run with the privileges of the user that created it use SECURITY DEFINER. See section at bottom of this page:

    https://www.postgresql.org/docs/current/sql-createfunction.html

    Writing SECURITY DEFINER Functions Safely

    for the do's and don'ts.

    Here is original function with SECURITY DEFINER:

    CREATE OR REPLACE PROCEDURE public.analyze_test(x character varying)
     LANGUAGE plpgsql SECURITY DEFINER
    AS $procedure$
    begin
        EXECUTE 'analyze ' || quote_ident(x);
    END;
    $procedure$