How to check whether a stored procedure exists on PostgreSQL? - postgresql

I'm pretty new to PostgreSQL and trying to learn PostgreSQL with the knowledge that I have on MS SQL Server & Oracle. I am looking for an equivalent of the following statement that we can use in MS SQL Server to check whether a Stored procedure exists or not, in PostgreSQL where SPName is your stored procedure's name.
SELECT 1 FROM sys.procedures WHERE Name = 'SPName')
SELECT 1 FROM sys.procedures WHERE object_id = OBJECT_ID(N'dbo.SPName')

SELECT EXISTS (
SELECT *
FROM pg_catalog.pg_proc
JOIN pg_namespace ON pg_catalog.pg_proc.pronamespace = pg_namespace.oid
WHERE proname = 'proc_name'
AND pg_namespace.nspname = 'schema_name'
)
If you've not created a specific schema then use public(pg_namespace.nspname = 'public')
OR
You can create a custom function to do the task like below:
create or replace function function_exists (sch text,fun text) returns boolean as
$$
begin
EXECUTE 'select pg_get_functiondef('''||sch||'.'||fun||'''::regprocedure)';
return true;
exception when others then
return false;
end;
$$ language plpgsql
and use :
select function_exists('public','function_name()')

Try like this:
SELECT EXISTS (
SELECT 1
FROM pg_proc JOIN pg_namespace on pg_proc.oid = pg_namespace.oid
WHERE pg_proc.proname = 'procedure name'
and pg_namespace.nspname = 'name' );

One-liner:
SELECT to_regproc('schema_name.proc_name') IS NOT NULL

Related

Using PERFORM in recursive query function in PostgreSQL

I have a recursive query which I want to use in PostgreSQL function, and it should return a Boolean value.
CREATE OR REPLACE FUNCTION store.is_item(object1 VARCHAR(40), object2 VARCHAR(40))
RETURNS BOOLEAN AS $$
BEGIN
WITH RECURSIVE externals AS (
SELECT object_id, used_id
FROM store.obj_depend
WHERE external = true
), history AS (
SELECT content_id AS id
FROM store.minfos
WHERE id= $2
UNION
SELECT externals.used_id
FROM externals
INNER JOIN history ON history.id = externals.object_id
),
PERFORM (SELECT c.id FROM store.cinfo AS c WHERE c.id = $1 INNER JOIN history
ON c.id = history.id);
RETURN FOUND;
END;
$$ LANGUAGE plpgsql;
When I try this it gives asyntax error at or near SELECT error.
The PERFORM is plpgsql statement and cannot be used inside any SQL command.
You can use PERFORM like proposed #klin, but then CTE is used inside a subquery, and subquery returns one row every time. Then a FOUND variable should be every time true.
In this case is better to use auxiliary variable as targer:
CREATE OR REPLACE FUNCTION store.is_item(object1 VARCHAR(40), object2 VARCHAR(40))
RETURNS BOOLEAN AS $$
DECLARE r record;
BEGIN
WITH RECURSIVE
externals AS (SELECT object_id, used_id
FROM store.obj_depend
WHERE external = true)
history AS (SELECT content_id AS id
FROM store.minfos
WHERE id = object2
UNION
SELECT externals.used_id
FROM externals
INNER JOIN history ON history.id = externals.object_id)
SELECT c.id
FROM store.cinfo AS c
INNER JOIN history ON c.id = history.id
WHERE c.id = $1
INTO r;
RETURN FOUND;
END;
$$ LANGUAGE plpgsql;

Get tablename from regclass in PostgreSQL

I would like to get Tablename from regclass in PostgreSQL. I have found a work around but I am not feeling so happy with it:
SELECT split_part('datastore.inline'::regclass::TEXT, '.', 2);
Is there a dedicated function to extract table name from regclass in Postgre?
You can query pg_class:
select relname
from pg_class
where oid = 'datastore.inline'::regclass;
There is no built-in function but you can create your own one:
create or replace function get_relname(regclass)
returns name language sql as $$
select relname
from pg_class
where oid = $1
$$;
select get_relname('datastore.inline'::regclass);

Query on subquery that gets tables' names

I have few tables in my database. They all have the same columns (id, name) but differ in the table name. Those tables have names that start with letter 'h'.
Not a very interesting schema design but I have to follow it.
I need to search for id in all those tables.
I tried something similar to:
select id from (select table_name
FROM information_schema.tables
where table_name like 'h%') as t;
I got error:
ERROR: column "id" does not exist.
I understand the error now but I still do not know how to do the query?
You need dynamic SQL to do that since you cannot use values as identifiers in plain SQL. Write a PL/pgSQL function with EXECUTE:
CREATE FUNCTION f_all_tables()
RETURNS TABLE (id int) AS
$func$
DECLARE
_tbl regclass;
BEGIN
FOR _tbl IN
SELECT c.oid::regclass
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND c.relname LIKE 'h%'
AND n.nspname = 'public' -- your schema name here
LOOP
RETURN QUERY EXECUTE '
SELECT id FROM ' || _tbl;
END LOOP;
END
$func$ LANGUAGE plpgsql;
I am using a variable of the object identifier type regclass to prevent SQL injection effectively. More about that in this related answer:
Table name as a PostgreSQL function parameter

creating an 'insert into' function using variables for schema names

I'm trying to create a function to insert data into a table. The query I'm using won't be changing except for the schema names need to be variables. For instance, one of my schema names is bscu.members and then there's 35 others which are very similar (wea.members, pcu.members.. etc etc..). I couldn't find any help on how to create a function in Postgresql using variables.
this is what i came up with so far but it isn't working
create or replace function attsummary(varchar)
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
insert into dwh.attribution_summary
select
m.source,
m.name,
m.partner_id,
d.ucic,
b.acct_type_desc as acct_desc,
a.begin_mo_balance as opening_balance,
c.date,
h.campaignname,
g.description as banner_desc,
f.create_time::timestamp as time_served,
'd' as dep_or_loan,
'h' as home_or_nonhome
from
$1.fact_deposits a
join $1.dim_acct_type b on a.acct_type_id = b.acct_type_id
join $1.dim_date c on a.date_id = c.date_id
join $1.dim_members d on a.ucic = d.ucic
join ad_delivery.sgmt_adic e on d.adic::varchar = e.adic
join ad_delivery.sgmt_user_tracker f on e.cookie_id = f.id
join ad_delivery.ox_banners g on g.bannerid = f.banner_id
join ad_delivery.ox_campaigns h on h.campaignid = f.campaign_id
join ad_delivery.sgmt_kli_adic i on e.adic = i.adic
join dwh.sgmt_clients m on m.partner_id = i.sgmt_partner_id
where
i.kli=8616208
and m.partner_id::integer != 909909
and then my select statement comes after.. I am using $1 for my variable where the schema name usually goes.
It must be dynamically generated
create or replace function attsummary
(schema text)
returns void as
$body$
begin
execute format('
insert into dwh.attribution_summary
select
m.source,
m.name,
m.partner_id,
d.ucic,
b.acct_type_desc as acct_desc,
a.begin_mo_balance as opening_balance,
c.date,
h.campaignname,
g.description as banner_desc,
f.create_time::timestamp as time_served,
''d'' as dep_or_loan,
''h'' as home_or_nonhome
from
%1$s.fact_deposits a
join %1$s.dim_acct_type b on a.acct_type_id = b.acct_type_id
join %1$s.dim_date c on a.date_id = c.date_id
join %1$s.dim_members d on a.ucic = d.ucic
join ad_delivery.sgmt_adic e on d.adic::varchar = e.adic
join ad_delivery.sgmt_user_tracker f on e.cookie_id = f.id
join ad_delivery.ox_banners g on g.bannerid = f.banner_id
join ad_delivery.ox_campaigns h on h.campaignid = f.campaign_id
join ad_delivery.sgmt_kli_adic i on e.adic = i.adic
join dwh.sgmt_clients m on m.partner_id = i.sgmt_partner_id
where
i.kli=8616208
and m.partner_id::integer != 909909
', $1);
end;
$body$
language plpgsql volatile
;
#Clodoaldo gave you a working answer, but note that the format() function he used isn't available prior to Pg 9.1. If you need this to work on older Pg instances you can use string expressions to build your dynamic query. Example:
CREATE SCHEMA a;
CREATE SCHEMA b;
CREATE TABLE a.foo ( data text );
CREATE TABLE b.foo ( data text );
CREATE OR REPLACE FUNCTION insert_with_schema(schema_name text, data text)
RETURNS void
AS $$
BEGIN
EXECUTE 'INSERT INTO ' || quote_ident(schema_name) || '.foo (data) VALUES ($1)'
USING data;
END
$$
LANGUAGE plpgsql;

How can you tell if a trigger is enabled in PostgreSQL?

My googling-fu is failing me. How to know if a PostgreSQL trigger is disabled or not?
The SQL below will do the work. It displays all triggers in your current database.
SELECT pg_namespace.nspname, pg_class.relname, pg_trigger.*
FROM pg_trigger
JOIN pg_class ON pg_trigger.tgrelid = pg_class.oid
JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
If tgenabled is 'D', the trigger is disabled. All other values (documented here) indicate, that it is enabled in some way.
BTW. If you want to check the triggers for a specific table, the query is a bit shorter:
SELECT * FROM pg_trigger
WHERE tgrelid = 'your_schema.your_table'::regclass
The cast to the regclass type gets you from qualified table name to OID (object id) the easy way.
It's my first day with postresql, but I think you can check the trigger state via pg_trigger system table: http://www.postgresql.org/docs/current/static/catalog-pg-trigger.html
The columns you will need are tgrelid and tgenabled.
SELECT EXISTS (
SELECT tgenabled
FROM pg_trigger
WHERE tgname='your_unique_trigger_name' AND
tgenabled != 'D'
);
If you know the trigger name is unique the above will return true (t) if the your_unique_trigger_name trigger is enabled:
exists
--------
t
(1 row)
If disabled it would return false (f).
Starting from #tolgayilmaz reply I created a simply function to be used around my project
CREATE OR REPLACE FUNCTION trigger_exists_on_table(schema_name text, table_name text, trigger_name text)
RETURNS boolean AS
$body$
declare
_sql text;
_boolean_exists boolean;
begin
_sql := format('
SELECT EXISTS (
SELECT 1
FROM pg_trigger
WHERE tgrelid = ''%s.%s''::regclass AND tgname = ''%s'' AND tgenabled != ''D''
)
', schema_name, table_name, trigger_name);
execute _sql into _boolean_exists;
return _boolean_exists;
end
$body$
LANGUAGE plpgsql;