How can I call a function from another schema in Postgresql? - sql

Tell me, how can I call a function from another schema in the trigger of an SQL function?
We have Postgresql, the main public schema and the amqp schema, which was formed when pg_amqp was connected.
The public schema has a trigger function for tracking INSERT/UPDATE/DELETE in the table:
if (TG_OP = 'INSERT') then
INSERT INTO table_1_audit_log (
table_1_id,
old_row_data,
new_row_data,
dml_type,
dml_timestamp
)
VALUES(
NEW.id,
null,
to_jsonb(NEW),
'INSERT',
CURRENT_TIMESTAMP
);
RETURN NEW;
elsif (TG_OP = 'UPDATE') then
INSERT INTO table_1_audit_log (
table_1_id,
old_row_data,
new_row_data,
dml_type,
dml_timestamp
)
VALUES(
NEW.id,
to_jsonb(OLD),
to_jsonb(NEW),
'UPDATE',
CURRENT_TIMESTAMP
);
RETURN NEW;
elsif (TG_OP = 'DELETE') then
INSERT INTO table_1_audit_log (
table_1_id,
old_row_data,
new_row_data,
dml_type,
dml_timestamp
)
VALUES(
OLD.id,
to_jsonb(OLD),
null,
'DELETE',
CURRENT_TIMESTAMP
);
RETURN OLD;
end if;
END;
I want to call the amqp.publish function from the amqp schema in this function:
SELECT amqp.publish(1, '', 'queu', 'messange')
But it gives me an error:
ERROR: function amqp.publish(integer, unknown, unknown, unknown) does not exist

It was necessary to set the types forcibly:
SELECT amqp.publish(1, ''::varchar, 'queu'::varchar, 'messange'::varchar)

Related

How to make and statement on IF trigger SQL?

I have a trigger and I have conditions in it, and I wanted to make something like this, but I can't manage to do it, I tried several things but none of them worked...
IF NEW.foo = OLD.foo AND NEW.bar = OLD.bar
THEN
...
RETURN NEW
END IF;
END;
CREATE OR REPLACE FUNCTION user_histo() RETURNS trigger AS $$
BEGIN
IF TG_OP = 'INSERT'
THEN
INSERT INTO table (attribute1, attribute2, attribute3, attribute4, attribute5, attribute6, attribute7)
VALUES (NEW.attribute1, NEW.attribute2, NEW.attribute3, NEW.attribute4, NEW.attribute5, NEW.attribute6, 'INSERT');
RETURN NEW;
ELSIF TG_OP = 'UPDATE'
THEN
IF (OLD.attribute2 = NEW.attribute2 AND OLD.attribute3 = NEW.attribute3) // this is my problem
THEN
INSERT INTO table (attribute1, attribute2, attribute3, attribute4, attribute5, attribute6, attribute7)
VALUES (OLD.attribute1, OLD.attribute2, OLD.attribute3, OLD.attribute4, OLD.attribute5, OLD.attribute6, 'UPDATE');
INSERT INTO table (attribute1, attribute2, attribute3, attribute4, attribute5, attribute6, attribute7)
VALUES (NEW.attribute1, NEW.attribute2, NEW.attribute3, NEW.attribute4, NEW.attribute5, NEW.attribute6, 'INSERT');
RETURN NEW;
ELSE
RETURN NULL;
END IF;
END IF;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
CREATE TRIGGER trigger_table AFTER INSERT OR UPDATE ON table
FOR EACH ROW EXECUTE PROCEDURE user_histo();

Error(20,56): PLS-00049: bad bind variable 'NEW.NEW_NAME'

I am facing this error while creating a trigger.
error - Error(20,56): PLS-00049: bad bind variable 'NEW.NEW_NAME'
if anyone can help it will be appreciated.
Please refer to my code below
Thanks in Advance :)
CREATE OR REPLACE TRIGGER insert_update_delete_employees AFTER
INSERT OR UPDATE OR DELETE ON employees
REFERENCING
OLD AS old
NEW AS new
FOR EACH ROW
ENABLE DECLARE
v_user VARCHAR2(20);
v_count NUMBER;
v_date VARCHAR2(20);
BEGIN
SELECT
user,
to_date(sysdate, 'DD/MON/YYYY HH24:MI:SS')
INTO
v_user,
v_date
FROM
dual;
SELECT
COUNT(1)
INTO v_count
FROM
employees;
IF updating THEN
INSERT INTO audit_table (
table_name,
user_name,
event,
event_date,
table_count,
new_object_name,
old_object_name
) VALUES (
'EMPLOYEES',
v_user,
'UPDATE',
v_date,
v_count,
:new.new_name,
NULL
);
dbms_output.put_line('Table data has been update by user ' || v_user);
SELECT
COUNT(*)
INTO v_count
FROM
employees;
ELSIF inserting THEN
INSERT INTO audit_table (
table_name,
user_name,
event,
event_date,
table_count,
new_object_name,
old_object_name
) VALUES (
'EMPLOYEES',
v_user,
'INSERT',
v_date,
v_count,
:new.new_name,
:old.old_name
);
dbms_output.put_line('Table data has been inserted by user ' || v_user);
SELECT
COUNT(*)
INTO v_count
FROM
employees;
ELSIF deleting THEN
INSERT INTO audit_table (
table_name,
user_name,
event,
event_date,
table_count,
new_object_name,
old_object_name
) VALUES (
'EMPLOYEES',
v_user,
'DELETE',
v_date,
v_count,
NULL,
:old.old_name
);
dbms_output.put_line('Table data has been deleted by user ' || v_user);
SELECT
COUNT(*)
INTO v_count
FROM
employees;`enter code here`
END IF;
END;
As you are using sample database schema, So please use :new.first_name column instead of :new.new_name

How to get the primary key value of a row in a function?

I have a function in postgres that sends events on CRUD operations in my tables. However the problem is that it only works for tables that have an id column which is the primary key. How can I change this so that I can use whatever column is the primary key?
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SET search_path = PUBLIC,
pg_catalog;
CREATE OR REPLACE FUNCTION psycopg2_pgevents_create_event() RETURNS TRIGGER AS $function$
BEGIN
IF (TG_OP = 'DELETE') THEN
PERFORM pg_notify('psycopg2_pgevents_channel',
json_build_object(
'event_id', uuid_generate_v4(),
'event_type', TG_OP,
'schema_name', TG_TABLE_SCHEMA,
'table_name', TG_TABLE_NAME,
'row_id', OLD.id -------- this is not always "id"
)::text
);
RETURN NULL;
ELSE
raise notice 'Value: %', NEW;
PERFORM pg_notify('psycopg2_pgevents_channel',
json_build_object(
'event_id', uuid_generate_v4(),
'event_type', TG_OP,
'schema_name', TG_TABLE_SCHEMA,
'table_name', TG_TABLE_NAME,
'row_id', NEW.id, -------- this is not always "id"
'data', NEW
)::text
);
RETURN NULL;
END IF;
END;
$function$ LANGUAGE PLPGSQL;
SET search_path = "$user",
PUBLIC;
If you only have a single primary key column, and you just want its value, you can extract it using:
to_jsonb(NEW)->>(
SELECT attname
FROM pg_attribute
JOIN pg_index ON indexrelid = attrelid
WHERE indrelid = TG_RELID
AND indisprimary
)
If you've got multiple primary key columns, and/or you want to retrieve the PK in {"key":"value"} format, you could use:
SELECT jsonb_object_agg(attname, to_jsonb(NEW)->attname)
FROM pg_attribute
JOIN pg_index ON indexrelid = attrelid
WHERE indrelid = TG_RELID
AND indisprimary

Insert data into staging table in databse trigger on main table

I have below requirement-
I have 2 tables Main Table A ,Staging table B
I have written a before insert trigger on main table A to check some wrong data. If the data is wrong then it will insert into staging table B so that user can view the errors and correct then and then again upload the data.
My issue is -Data is not getting inserted into staging table as I am using raise_form_trigger_failure just after insert statement.Is there any other way to do this?
TRIGGER CODE-
create or replace trigger CCM_TEST
before insert OR UPDATE ON "CCM_MANAGER"
for each row
declare
l_user varchar2(500);
v_user number;
v_cost_centre number;
v_company_code number;
v_show_error varchar2(100);
begin
l_user := NVL(v('APP_USER'), user);
if inserting then
begin
select count(1)
into v_cost_centre
From gl_code_combinations
where segment2=:new.cost_center
and enabled_flag ='Y';
if (v_cost_centre= 0) then
v_show_error:='Cost Centre does not exists!! '||'Cost Centre -'||:new.cost_center;
:new.CHECK_INSERT_FLAG:='Y';
Insert into CCM_MANAGER_STG(COMPANY_CODE,
COST_CENTER,
USER_NAME,
EFFECTIVE_START_DATE,
EFFECTIVE_END_DATE,
CREATED_BY,
CREATION_DATE,
LAST_UPDATED_BY,
LAST_UPDATE_DATE,
LINE_ID,
CHECK_INSERT_FLAG,
SHOW_ERRORS) values
( :new.COMPANY_CODE,
:new.COST_CENTER,
:new.USER_NAME,
:new.EFFECTIVE_START_DATE,
:new.EFFECTIVE_END_DATE,
:new.CREATED_BY,
:new.CREATION_DATE,
:new.LAST_UPDATED_BY,
:new.LAST_UPDATE_DATE,
:new.LINE_ID,
:new.CHECK_INSERT_FLAG,
v_show_error);
end if;
raise_application_error (-20001, 'Cost Centre does not exists!! '||'Cost Centre -'||:new.cost_center||' ');
exception
when others then
--raise_application_error (-20001, sqlerrm);
null;
end;
begin
select count(1)
into v_company_code
From gl_code_combinations
where segment1=:new.company_code
and enabled_flag ='Y';
if (v_company_code= 0) then
v_show_error:='Company Code does not exists!!';
:new.CHECK_INSERT_FLAG:='Y';
Insert into CCM_MANAGER_STG(COMPANY_CODE,
COST_CENTER,
USER_NAME,
EFFECTIVE_START_DATE,
EFFECTIVE_END_DATE,
CREATED_BY,
CREATION_DATE,
LAST_UPDATED_BY,
LAST_UPDATE_DATE,
LINE_ID,
CHECK_INSERT_FLAG,
SHOW_ERRORS) values
( :new.COMPANY_CODE,
:new.COST_CENTER,
:new.USER_NAME,
:new.EFFECTIVE_START_DATE,
:new.EFFECTIVE_END_DATE,
:new.CREATED_BY,
:new.CREATION_DATE,
:new.LAST_UPDATED_BY,
:new.LAST_UPDATE_DATE,
:new.LINE_ID,
:new.CHECK_INSERT_FLAG,
v_show_error);
end if;
raise_application_error (-20001, 'Company Code does not exists!! '||'Company code -'||:new.company_code||' ');
-- Rollback;
exception
when others then
raise_application_error (-20001, sqlerrm);
null;
end;
end if;
end;
First way is autonomous transaction.
Second way is compound trigger.

how we send parameters to trigger function which is not related to affected table in PostgreSQL

CREATE TABLE emp (
empname text NOT NULL,
salary integer
);
CREATE TABLE emp_audit(
operation char(1) NOT NULL,
stamp timestamp NOT NULL,
userid text NOT NULL,
empname text NOT NULL,
salary integer
);
CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$
BEGIN
--
-- Create a row in emp_audit to reflect the operation performed on emp,
-- make use of the special variable TG_OP to work out the operation.
--
IF (TG_OP = 'DELETE') THEN
INSERT INTO emp_audit SELECT 'D', now(), user_id, OLD.*;
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO emp_audit SELECT 'U', now(), user_id, OLD.*;
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO emp_audit SELECT 'I', now(), user_id, NEW.*;
RETURN NEW;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
$emp_audit$ LANGUAGE plpgsql;
DROP TRIGGER emp_audit ON emp;
CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();
user_id not in emp table
can we send parameters to trigger function which is not related to affected table in PostgreSQL. if I enter an active record of user there may some issue as if two different users active then trigger will confuse