SEARCH_PATH
for any function manually and then functions from other schema will be invisible. But this design is pretty frail. Somebody can call functions from other schema by qualified name, and the often switch of SEARCH_PATH
in significantly decrease readability of your code.I think so some convention can help. For example, we can mark of any private functions by prefix '_'. With
plpgsql_check
we can check if these functions are used only inside functions with same schema. The plpgsql_check
's function plpgsql_show_dependency_tb
does this work.CREATE SCHEMA packagex; /* * private function, should be used only by functions from this schema */ CREATE OR REPLACE FUNCTION packagex._privatefx(a integer) RETURNS integer AS $$ BEGIN RETURN a; END; $$ LANGUAGE plpgsql; /* * public function - use private function correctly */ CREATE OR REPLACE FUNCTION packagex.publicf1(a integer) RETURNS integer AS $$ BEGIN RETURN packagex._privatefx(a); END; $$ LANGUAGE plpgsql; /* * public function - doesn't use private function correctly */ CREATE OR REPLACE FUNCTION public.publicf2(a integer) RETURNS integer AS $$ BEGIN RETURN packagex._privatefx(a); END; $$ LANGUAGE plpgsql;
The function
public.publicf2
is breaking our convention and I have to identify this function.SELECT * FROM (SELECT pronamespace::regnamespace, proname, x.* FROM pg_proc, plpgsql_show_dependency_tb(oid) x WHERE prolang = (SELECT oid FROM pg_language WHERE lanname = 'plpgsql') AND pronamespace <> 'pg_catalog'::regnamespace) s WHERE starts_with(name, '_') AND schema::regnamespace <> pronamespace; ┌──────────────┬──────────┬──────────┬───────┬──────────┬────────────┬───────────┐ │ pronamespace │ proname │ type │ oid │ schema │ name │ params │ ╞══════════════╪══════════╪══════════╪═══════╪══════════╪════════════╪═══════════╡ │ public │ publicf2 │ FUNCTION │ 16411 │ packagex │ _privatefx │ (integer) │ └──────────────┴──────────┴──────────┴───────┴──────────┴────────────┴───────────┘ (1 row)
There is not nice possibility how to implement private functions in Postgres now, but we can introduce some conventions and we can check if these conventions are broken or not.
The function
plpgsql_show_dependency_tb
display all objects used by function:SELECT pg_proc.oid::regprocedure AS function, x.oid::regprocedure AS "called function" FROM pg_proc, plpgsql_show_dependency_tb(oid) x WHERE prolang = (SELECT oid FROM pg_language WHERE lanname = 'plpgsql') AND pronamespace <> 'pg_catalog'::regnamespace AND x.type = 'FUNCTION'; ┌────────────────────────────┬──────────────────────────────┐ │ function │ called function │ ╞════════════════════════════╪══════════════════════════════╡ │ packagex.publicf1(integer) │ packagex._privatefx(integer) │ │ publicf2(integer) │ packagex._privatefx(integer) │ └────────────────────────────┴──────────────────────────────┘ (2 rows)
No comments:
Post a Comment