Insert string contains '$$' in postgresql - postgresql

I have a issue when I try to insert into users table.
DO $$
DECLARE newId bigint;
BEGIN
INSERT INTO users("email","bio","status","created_by","updated_by")
VALUES ('tetsinsert#gmail.com','❄❄Haocute$$','accepted','1','1')
RETURNING id INTO newId;
UPDATE synces SET "version" = "version" + 1, updated_at = now(),
new_id = newId WHERE "old_id" = 98525 and table_name = 'users';
IF NOT FOUND THEN
INSERT INTO synces
(created_at, updated_at, deleted_at, table_name, old_id, new_id, "version")
VALUES(now(), now(), null, 'users', 98525, newId, 0);
END IF;
END $$
Thank you for reading my post.

There are two possibilities:
use different custom string separator:
do $my_custom_string_separator$
begin
raise notice '❄❄Haocute$$';
end
$my_custom_string_separator$;
NOTICE: ❄❄Haocute$$
DO
You can use extended strings with escaped values:
do $$
begin
raise notice e'❄❄Haocute\$\$';
end
$$;
NOTICE: ❄❄Haocute$$
DO

I found a solution
DO $do$
DECLARE newId bigint;
BEGIN
INSERT INTO users("email","bio","status","created_by","updated_by")
VALUES ('tetsinsert#gmail.com','❄❄Haocute$$','accepted','1','1')
RETURNING id INTO newId;
UPDATE synces SET "version" = "version" + 1, updated_at = now(),
new_id = newId WHERE "old_id" = 98525 and table_name = 'users';
IF NOT FOUND THEN
INSERT INTO synces
(created_at, updated_at, deleted_at, table_name, old_id, new_id, "version")
VALUES(now(), now(), null, 'users', 98525, newId, 0);
END IF;
END $do$

Related

How insert count of a table in another table attribute by trigger postgresql

I have created two tables "post" and "node" and I want to assign the sum of the entities of the "node" table in the attribute "nb_noeud" of the "post" table by trigger. But, the code below does not work and I think I missed something.
My code is as follows:
CREATE TABLE noeud
(
id_noeud serial NOT NULL,
code_noeud varchar(10) NULL,
type_noeud t_noeud NULL,
phase t_phase NULL
x_32632 bigint NULL,
y_32632 bigint NULL,
geom_noeud geometry(point) NULL,
obs text NULL
)
;
CREATE TABLE poste
(
id_pt serial NOT NULL,
code_pt varchar(8) NULL,
nom_pt varchar(50) NULL,
nb_noeud smallint NULL,
geom_pt geometry(polygon) NULL,
surf_pt numeric(15,2) NULL,
obs text NULL
)
;
CREATE OR REPLACE FUNCTION recap_noeud() RETURNS TRIGGER
language plpgsql AS
$$
DECLARE
som_noeud smallint;
BEGIN
IF (TG_OP = 'INSERT') THEN
SELECT COUNT(*) INTO som_noeud FROM noeud;
UPDATE poste set NEW.nb_noeud = som_noeud;
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
SELECT COUNT(*) INTO som_noeud FROM noeud;
UPDATE poste set NEW.nb_noeud = som_noeud;
RETURN NEW;
ELSIF (TG_OP = 'UPDATE') THEN
RETURN NULL;
ELSE
RAISE WARNING 'Other action occurred: %, at %', TG_OP, now();
RETURN NULL;
END IF;
END;
$$
;
DROP TRIGGER IF EXISTS trig_recap_noeud ON noeud;
CREATE TRIGGER trig_recap_noeud AFTER INSERT OR UPDATE OR DELETE ON noeud FOR EACH ROW EXECUTE PROCEDURE recap_noeud();
Replace DELETE and INSERT clauses with
IF TG_OP = 'INSERT' OR TG_OP = 'DELETE' THEN
SELECT COUNT(*) INTO som_noeud FROM noeud;
UPDATE poste set nb_noeud = som_noeud;
RETURN NULL;
Best regards, Bjarni

trigger in postgresql old value and new value

how to write trigger in postgresql which maintain old value, new value and table name.
I have 5 tables and each tables is different data structure i want to maintain audit details in single table with old value new value and table name.old value and new value contain multiple columns in json format with column name and value.
example
audit_details
----------------------------------------------------------------
date_time|table_name|old_data|new_data|user|primary_key_of_table
----------------------------------------------------------------
I wrote sample trigger function for you. You can make additional changes yourself.
CREATE TABLE test.log_table_data (
id serial not null,
schema_name varchar(100) NOT NULL,
table_name varchar(100) NOT NULL,
action_date timestamp NOT NULL DEFAULT now(),
action_type varchar(10) NOT NULL,
table_id int4 NOT NULL,
old_data jsonb NULL,
new_data jsonb NULL,
CONSTRAINT log_table_data_pk PRIMARY KEY (id)
);
create or replace function test.register_as_log()
returns trigger
language plpgsql
security definer
as $function$
declare
v_old_data json;
v_new_data json;
shemaname varchar;
tablename varchar;
begin
shemaname = tg_table_schema;
tablename = tg_table_name;
/* json_strip_nulls - removes null values */
if (tg_op = 'UPDATE') then
v_old_data = (select json_strip_nulls(row_to_json(old.*)));
v_new_data = (select json_strip_nulls(row_to_json(new.*)));
insert into test.log_table_data (schema_name, table_name, action_type, table_id, old_data, new_data)
values (shemaname, tablename, 'update', old.id, v_old_data, v_new_data);
return new;
end if;
if (tg_op = 'DELETE') then
v_old_data = (select json_strip_nulls(row_to_json(old.*)));
insert into test.log_table_data (schema_name, table_name, action_type, table_id, old_data, new_data)
values (shemaname, tablename, 'delete', old.id, v_old_data, null);
return old;
end if;
end;
$function$
;

Postgres mistakes parameter for column

I am new to Postgres DBs, and I am trying to write a function (like a stored procedure) to all inserting a user into my database. I know I must be missing something obvious, but I keep getting an error in the code shown where Postgres says { error: column "p_organizationsid" does not exist }. This is the snippet of code that appears to be causing the problem.
CREATE OR REPLACE FUNCTION userupsertget(
p_id uuid,
p_username character varying,
p_organizationid uuid,
p_organizationsid character varying,
p_lastname character varying,
p_firstname character varying,
p_middleinitial character varying,
p_emailaddress character varying,
p_sid character varying,
p_languageid integer,
p_forcepasswordreset bit,
p_salt character varying,
p_hash character varying,
p_statusid uuid,
p_createdby uuid,
p_modifiedby uuid,
p_lastsessionuguid uuid,
p_roleids uuid[],
p_applicationid uuid)
RETURNS SETOF users
LANGUAGE 'plpgsql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
BEGIN
DO
$do$
DECLARE establishedOrgID uuid;
BEGIN
SELECT org.id FROM organization AS org
WHERE org.sid = p_organizationsid
OR org.id = p_organizationid;
IF EXISTS (SELECT 1 FROM users WHERE id = p_id) THEN
--update statement;
UPDATE users
SET username = p_username,
lastname = p_lastname,
firstname = p_firstname,
middleinitial = p_middleinitial,
emailaddress = p_emailaddress,
sid = p_sid,
languageid = p_languageid,
forcepasswordreset = p_forcepasswordreset,
statusid = p_statusid,
datemodified = current_timestamp,
createdby = p_createdby,
modifiedby = p_modifiedby,
lastsessionguid = p_lastsessionguid
WHERE id = p_id;
IF EXISTS (SELECT 1 FROM users WHERE id = p_id AND statusid <> p_statuid) THEN
UPDATE users SET statusid = p_statusid, datestatusmodified = current_timestamp WHERE id = p_id;
END IF;
ELSE
INSERT INTO users (id, organizationid, username, lastname, firstname, middleinitial,
emailaddress, sid, languageid, forcepasswordreset, statusid, datecreated,
datemodified, createdby, modifiedby, lastsessionguid)
SELECT p_id, establishedOrgID, p_username, p_lastname, p_firstname, p_middleinitial, p_emailaddress, p_sid,
p_languageid, p_forcepasswordreset, p_statusid, current_timestamp, current_timestamp,
p_createdby, p_modifiedby, p_lastsessionuguid
FROM users
WHERE id = p_id;
-- DECLARE newid uuid := LASTVAL();
INSERT INTO users (id, userid, roleid, applicationid, startdate, enddate, createdby, modifiedBy)
SELECT LASTVAL(), roleid, p_applicationid, current_timestamp, current_timestamp, p_createdby, p_modifiedby
FROM UNNEST (p_roleids) AS roleids;
END IF;
END
$do$;
RETURN QUERY
SELECT usr.*, org.uselogin
FROM users AS usr
INNER JOIN organization AS org On org.id = usr.organizationid
WHERE id = p_id;
END;
$BODY$;
As you can see in the PostgreSQL documentation about Creating a function: https://www.postgresql.org/docs/9.1/sql-createfunction.html
you should get better luck if you replace your parameter's name by $n where n is the number of the function parameter:
CREATE FUNCTION add(integer, integer) RETURNS integer
AS 'select $1 + $2;'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
or...
CREATE FUNCTION check_password(uname TEXT, pass TEXT)
RETURNS BOOLEAN AS $$
DECLARE passed BOOLEAN;
BEGIN
SELECT (pwd = $2) INTO passed
FROM pwds
WHERE username = $1;
RETURN passed;
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER
-- Set a secure search_path: trusted schema(s), then 'pg_temp'.
SET search_path = admin, pg_temp;
Now, if you wish to continue using parameter names, you should declare them as alias:
CREATE or REPLACE FUNCTION data_ctl(opcao char, fdata date, fhora time) RETURNS char(10) AS $$
DECLARE
opcao ALIAS FOR $1;
vdata ALIAS FOR $2;
vhora ALIAS FOR $3;
retorno char(10);
BEGIN
IF opcao = 'I' THEN
insert into datas (data, hora) values (vdata, vhora);
retorno := 'INSERT';
END IF;
IF opcao = 'U' THEN
update datas set data = vdata, hora = vhora where data='1995-11-01';
retorno := 'UPDATE';
END IF;
IF opcao = 'D' THEN
delete from datas where data = vdata;
retorno := 'DELETE';
ELSE
retorno := 'NENHUMA';
END IF;
RETURN retorno;
END;
$$
LANGUAGE plpgsql;
--select data_ctl('I','1996-11-01', '08:15');
select data_ctl('U','1997-11-01','06:36');
select data_ctl('U','1997-11-01','06:36');

PL/pgSQL: How to use IF NEW.<variable_column_name> <> OLD.<variable_column_name>

I am pretty new to PL/pgSQL programming. I have a requirement of audit logging updated columns in my table
Table
create table sample_table(name varchar(15),city varchar(15),age int,mail varchar(20) primary key);
Audit table
create table sample_table__audits_dynamicols(mail varchar(20), columnchanged varchar(10), oldvalue varchar(10), changed_on timestamp(6) NOT NULL)
Trigger Function
CREATE FUNCTION public.log_sample_table_allchanges() RETURNS trigger AS $BODY$DECLARE
_colname text;
_tablename varchar(15) := 'sample_table';
_schema varchar(15) := 'public';
_changed_on time := now();
BEGIN
FOR _colname IN SELECT column_name FROM information_schema.Columns WHERE table_schema = _schema AND table_name = _tablename LOOP
IF NEW._colname <> OLD._colname THEN
INSERT INTO sample_table__audits_dynamicols(mail,columnchanged, oldvalue ,changed_on)
VALUES(OLD.mail,_colname,OLD.:_colname,_changed_on);
END IF;
END LOOP;
RETURN NEW;
END$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;
Trigger
create TRIGGER log_sample_table_allchanges
BEFORE UPDATE
ON SAMPLE_TABLE
FOR EACH ROW
EXECUTE PROCEDURE log_sample_table_allchanges();
Requirement: Whenever a column value is changed i want to log it as
(mail, columnname, columnvalue, date)
E.g:
insert into sample_table (name, mail, city, age) values('kanta','mk#foo.com','hyd',23);
insert into sample_table (name, mail, city, age) values('kmk','mk#gmail.com','hyd',23);
So when i update like the following
update sample_table set age=24 where mail='mk#foo.com';
update sample_table set city='bza' where mail='mk#gmail.com'
I want audit table to record like
(mk#foo.com,age,23, timestamp)
(mk#gmail.com, city, hyd, timestamp)
Right now I am facing issue with column comparison in my Trigger function. Please help me rectifying my Trigger function to meet my requirement.
You may use EXECUTE to get the values of columns dynamically and do the comparison.
CREATE OR REPLACE FUNCTION public.log_sample_table_allchanges() RETURNS trigger AS
$BODY$
DECLARE
_colname text;
_tablename varchar(15) := 'sample_table';
_schema varchar(15) := 'public';
_changed_on timestamp := now();
_old_val text;
_new_val text;
BEGIN
FOR _colname IN SELECT column_name FROM information_schema.Columns WHERE table_schema = _schema AND table_name = _tablename
LOOP
EXECUTE 'SELECT $1.' || _colname || ', $2.' || _colname
USING OLD,NEW
INTO _old_val, _new_val; --get the old and new values for the column.
IF _new_val <> _old_val THEN
INSERT INTO sample_table__audits_dynamicols(mail,columnchanged, oldvalue ,changed_on)
VALUES(OLD.mail,_colname,_old_val,_changed_on);
END IF;
END LOOP;
RETURN NEW;
END$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;
I'm not sure why you have defined mail as a PRIMARY KEY in the audits table, it will cause unique constraint violation if the same mail gets updated twice.

Issue with dynamic sql

Hi every one I have multiple spatial tables That I want to control, so that I created a table where I will store the name of the operation applied on my layers tables(insert,update or delete), operation time and the team who did it, number of spatial tables created.
My script table
CREATE TABLE public.monitoring_table
(
operation character(1) COLLATE pg_catalog."default",
operat_ime timestamp without time zone,
userid text COLLATE pg_catalog."default",
dc_team text COLLATE pg_catalog."default",
number_pts_created integer,
id integer NOT NULL DEFAULT nextval('monitoring_table_id_seq'::regclass),
CONSTRAINT monitoring_table_pkey PRIMARY KEY (id)
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.monitoring_table
OWNER to postgres;
after that I stored all the teams that I have on my table :
insert into monitoring_table (dc_team) values ('abdoulhassan');
insert into monitoring_table (dc_team) values ('abdoulei');
insert into monitoring_table (dc_team) values ('danis');
insert into monitoring_table (dc_team) values ('david');
insert into monitoring_table (dc_team) values ('joseph');
To calculate the number of spatial tables created, I executed this function :
My counting function :
DROP FUNCTION get_dc_team_counting();
CREATE OR REPLACE FUNCTION get_dc_team_counting()
RETURNS bigint AS
$func$
DECLARE
dc_team text;
_tbl_pattern text;
_schema text = 'sige';
_tb_name information_schema.tables.table_name%TYPE;
_tc bigint;
BEGIN
FOR _tb_name IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = _schema
AND table_name ~ _tbl_pattern
LOOP
EXECUTE format('SELECT count(*) FROM %I.%I where id= 583', _schema, _tb_name)
INTO _tc;
return _tc;
END LOOP;
END
$func$ LANGUAGE plpgsql
To get the team I executed this function :
CREATE OR REPLACE FUNCTION get_team()
RETURNS text AS -- or whatever you want to return
$func$
DECLARE
dc_team text;
_tbl_pattern text;
_schema text = 'public';
_tb_name information_schema.tables.table_name%TYPE; -- currently varchar
_tc text;
BEGIN
FOR _tb_name IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = _schema
AND table_name ~ _tbl_pattern -- see below!
LOOP
EXECUTE format('SELECT dc_team FROM %I.%I where id = 26', _schema, _tb_name)
INTO _tc;
return _tc;
END LOOP;
END
$func$ LANGUAGE plpgsql;
In my where clause I want to get dynamically the value of the ID. I don't want to give it manually in the function. I don't see how to do it.
Now I created a trigger function to be able to update my table if a row was inserted, updated or deleted. I did it this way :
CREATE OR REPLACE FUNCTION process_monitoring() RETURNS TRIGGER AS $monitoring$
BEGIN
IF (TG_OP = 'DELETE') THEN
update monitoring_table set operation = 'D', operat_ime = now(), userid = user ,dc_team = OLD.dc_team, number_pts_created = get_dc_team_counting() where dc_team = get_team();
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
update monitoring_table set operation = 'U',operat_ime = now(),userid = user , dc_team = NEW.dc_team, number_pts_created = get_dc_team_counting() where dc_team = get_team();
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
update monitoring_table set operation = 'I', operat_ime = now(), userid = user, dc_team = NEW.dc_team, number_pts_created = get_dc_team_counting() where dc_team = get_team();
RETURN NEW;
END IF;
RETURN NULL;
END;
$monitoring$ LANGUAGE plpgsql;
CREATE TRIGGER monitoring
AFTER INSERT OR UPDATE OR DELETE ON sige.valve
FOR EACH ROW EXECUTE PROCEDURE process_monitoring();
In my previous functions I used known values of ids in the where clauses, but when I try to insert or update a value on the concerned table I get this error :
the control attempted it's end without return
CONTEXT: fonction PL/pgsql get_team()
instruction SQL « update monitoring_table set operation = 'U',operat_ime = now(),userid = user , dc_team = NEW.dc_team, number_pts_created = get_dc_team_counting() where dc_team = get_team() »
fonction PL/pgsql process_monitoring(), ligne 10 à instruction SQL
If you have any idea about the origin of the error and how to get dynamically a value of a field and put it in the where clause tell me please.
I'm a newbie and I'm struggling, any assistance would be warmly appreciated.
I'm using PostgreSQL.