Postgres 8.3 Query full function definition using a query

拥有回忆 提交于 2019-12-13 03:57:15

问题


Is it possible to be able to retrieve the full function definition (with parameters etc) using a SQL query?


回答1:


This function or view (doing similar things) works with Postgres 8.3.

CREATE AGGREGATE public.textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

CREATE OR REPLACE FUNCTION public.getfunctionddl(functionOid oid)
  RETURNS text AS
$BODY$
DECLARE
    funcschema text;
    funcname text = NULL;
    paranames text;
    paramodes text;
    paratypes text;
    paraintypes text;
    function_body text = NULL;
    paranames_array text[];
    paramodes_array text[];
    paratypes_array text[];
    params_sql text = '';
    type_name text = '';
    return_type text;
    params_sql_no_name text ='';
    grants text;
    proc_owner text;
    proacl_txt text;
    lanname_txt text;
    function_sql text;
    upper_array int;
    in_param_cnt int = 0;
    out_param_cnt int = 0;
    prosecdef_b bool;
    pro_volatile text;
    pro_isstrict bool;
BEGIN
SELECT proargtypes, proallargtypes, proargnames, proargmodes, prosrc, ns.nspname, p.proname, prorettype, proacl, lanname, prosecdef, rolname, provolatile, proisstrict
INTO paraintypes, paratypes, paranames, paramodes, function_body, funcschema, funcname, return_type, proacl_txt, lanname_txt, prosecdef_b, proc_owner, pro_volatile, pro_isstrict
FROM pg_proc p
INNER JOIN pg_namespace ns ON ns.oid = p.pronamespace
INNER JOIN pg_language pl ON pl.oid = prolang
INNER JOIN pg_roles rl ON rl.oid = proowner
WHERE p.oid = functionOid
AND lanname <> 'internal';

IF COALESCE(funcname, '') = '' THEN
    RETURN NULL;
END IF;

paratypes := REPLACE(COALESCE(paratypes, paraintypes), ',', ' ');
return_type := format_type(return_type::oid,NULL);
return_type := CASE WHEN return_type = 'character varying' THEN 'varchar' ELSE return_type END;
if paranames IS NULL OR paranames = '' THEN
    params_sql := '()';
    params_sql_no_name := '()';
ELSE
    paratypes := REPLACE(REPLACE(paratypes, '{', ''), '}', '');
    paranames := REPLACE(REPLACE(paranames, '{', ''), '}', '');
    paramodes := REPLACE(REPLACE(paramodes, '{', ''), '}', '');

    paratypes_array:=string_to_array(paratypes,' ');
    paranames_array:=string_to_array(paranames,',');
    paramodes_array:=string_to_array(paramodes,',');
    upper_array := array_upper(paratypes_array,1);
    params_sql := '(' || CASE WHEN upper_array > 5 THEN '
    ' ELSE '' END;
    params_sql_no_name := '(';
    FOR i IN array_lower(paratypes_array,1) .. array_upper(paratypes_array,1)
    LOOP
        type_name := format_type(paratypes_array[i]::oid, NULL);
        type_name := CASE WHEN type_name = 'character varying' THEN 'varchar' ELSE type_name END;
        params_sql := params_sql || CASE WHEN paramodes IS NULL OR paramodes = '' THEN '' WHEN paramodes_array[i] = 'o' THEN 'OUT ' ELSE '' END || paranames_array[i] || ' ' || type_name || CASE WHEN i = upper_array THEN ')' WHEN upper_array <= 5 THEN ', ' ELSE ',
    ' END;
        params_sql_no_name := params_sql_no_name || CASE WHEN paramodes IS NULL OR paramodes = '' THEN '' WHEN paramodes_array[i] = 'o' THEN 'OUT ' ELSE '' END || type_name || CASE WHEN i = upper_array THEN ')' ELSE ',' END;
        in_param_cnt := in_param_cnt + CASE WHEN paramodes IS NULL OR paramodes = '' THEN 1 WHEN paramodes_array[i] = 'o' THEN 0 ELSE 1 END;
        out_param_cnt := out_param_cnt + CASE WHEN paramodes IS NULL OR paramodes = '' THEN 0 WHEN paramodes_array[i] = 'o' THEN 1 ELSE 0 END;
    END LOOP;
END IF;

params_sql_no_name := LOWER(quote_ident(funcschema) || '.' || quote_ident(funcname)) || params_sql_no_name || '';
params_sql := quote_ident(funcschema) || '.' || quote_ident(funcname) || params_sql;

SELECT public.textcat_all('GRANT EXECUTE ON FUNCTION ' || params_sql_no_name || ' TO ' || quote_ident(grantee) || ';

') INTO grants
FROM(SELECT
      substring(a, 1, position('=X' in a) -1) as grantee
--  , substring(a, position('=X' in a) + 3, char_length(a) - position('=X' in a)) as grantor_name
From regexp_split_to_table(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(proacl_txt, '}', ''), '{', ''), CHR(34) || chr(92), ''), CHR(34), ''), chr(92), ''), ',') a)k
WHERE grantee <> proc_owner
AND grantee <> '';

function_sql := '-- ' || params_sql_no_name || '
' || CASE WHEN in_param_cnt + out_param_cnt > 0 THEN '-- PARAMS ALL: ' || CAST(in_param_cnt + out_param_cnt as char(3)) || ', IN: ' || cast(in_param_cnt as char(3)) || ', OUT ' || CAST(out_param_cnt as char(3)) || '
' ELSE '' END || '
-- DROP FUNCTION IF EXISTS ' || params_sql_no_name || ';
-- DROP FUNCTION IF EXISTS ' || params_sql_no_name || ' CASCADE;

CREATE OR REPLACE FUNCTION ' || params_sql || '
' || 'RETURNS ' || CASE WHEN return_type = 'record' then 'SETOF record' ELSE return_type END || '
LANGUAGE ' || lanname_txt || CASE WHEN pro_volatile = 'i' THEN ' IMMUTABLE' WHEN pro_volatile = 's' THEN ' STABLE' ELSE '' END || CASE WHEN pro_isstrict = true THEN ' RETURNS NULL ON NULL INPUT' ELSE '' END || CASE WHEN prosecdef_b = true THEN ' SECURITY DEFINER' ELSE '' END || '
AS $' || '$' || COALESCE(function_body, '') || '$' || '$;';

function_sql := function_sql || '

-- ALTER FUNCTION ' || params_sql_no_name || ' OWNER TO ' || quote_ident(proc_owner) || ';' || COALESCE('

' || grants, '');

RETURN function_sql;
END $BODY$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION public.getfunctionddl(schema_name_like varchar(256), function_name_like varchar(256), OUT schema_name varchar(256), OUT function_name varchar(256), OUT owner varchar(256), OUT func_lang varchar(256), OUT arg_cnt smallint, OUT func_oid oid, OUT ddl text)
RETURNS SETOF record AS $$
SELECT
      CAST(ns.nspname as varchar(256)) as schema_name
    , CAST(p.proname as varchar(256)) as proc_name
    , cast(rolname as varchar(256)) as owner
    , CAST(lanname as varchar(256)) as func_lang
    , p.pronargs as arg_cnt
    , p.oid as func_oid
    , public.getfunctionddl(p.oid) as ddl
FROM pg_proc p
INNER JOIN pg_namespace ns ON ns.oid = p.pronamespace
INNER JOIN pg_language pl ON pl.oid = prolang
INNER JOIN pg_roles rl ON rl.oid = proowner
WHERE ns.nspname ILIKE lower(coalesce($1, '%'))
AND p.proname ILIKE lower(coalesce($2, '%'))
AND lanname <> 'internal'
ORDER BY ns.nspname, p.proname, p.oid;
$$ LANGUAGE SQL;

CREATE OR REPLACE VIEW public.vw_functionddl
AS
SELECT
      CAST(ns.nspname as varchar(256)) as schema_name
    , CAST(p.proname as varchar(256)) as proc_name
    , cast(rolname as varchar(256)) as owner
    , CAST(lanname as varchar(256)) as func_lang
    , p.pronargs as arg_cnt
    , p.oid as func_oid
    , public.getfunctionddl(p.oid) as DDL
--  , proargtypes, proallargtypes, proargnames, proargmodes, prosrc, ns.nspname, p.proname, prorettype, proacl, prosecdef, rolname, provolatile, proisstrict
--  , p.*
FROM pg_proc p
INNER JOIN pg_namespace ns ON ns.oid = p.pronamespace
INNER JOIN pg_language pl ON pl.oid = prolang
INNER JOIN pg_roles rl ON rl.oid = proowner
WHERE lanname <> 'internal';

SELECT * FROM public.getfunctionddl('%' /*schema_name_like*/,'test_func' /*function_name_like*/);
SELECT * FROM public.vw_functionddl;


来源:https://stackoverflow.com/questions/53017223/postgres-8-3-query-full-function-definition-using-a-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!