Checking Function Parameter Postgres - postgresql

i'm trying to find the fastest way to check whether my postgres function parameter is null or empty.
my current function looks like:
CREATE OR REPLATE FUNCTON update_seller_detail(seller_id int,
seller_name varchar, seller_address varchar, seller_gender varchar)
RETURNS character varying
LANGUAGE plpsql
SECURITY DEFINER
AS $function$
BEGIN
IF seller_id = '' THEN
RAISE NOTICE 'Check Parameter'
return -1
ELSE
IF seller_name = '' THEN
UPDATE seller SET address=seller_address, gender=seller_gender WHERE id=seller_id;
ELSEIF seller_address = '' THEN
UPDATE seller SET name=seller_name, gender=seller_gender WHERE id=seller_id;
ELSE seller_gender= '' THEN
UPDATE seller SET name=seller_name, address=seller_address WHERE id=seller_id;
END IF;
END IF;
END;
$function$
Is there any way to find which of the parameter is null? so i can set my update to the column that's not null. thanks

you can use coalesce(nullif(trim(<column-reference>), '') in update query with column reference:
CREATE OR REPLACE FUNCTION update_seller_detail(
seller_id int,
seller_name varchar,
seller_address varchar,
seller_gender varchar
)
RETURNS character varying
LANGUAGE plpgsql
SECURITY DEFINER
AS
$function$
BEGIN
IF seller_id ISNULL THEN
RAISE NOTICE 'Check Parameter';
return -1;
ELSE
UPDATE public.seller s
SET name = coalesce(nullif(trim(seller_name), ''), s.name),
address = coalesce(nullif(trim(seller_address), ''), s.address),
gender = coalesce(nullif(trim(seller_gender), ''), s.gender)
WHERE id = seller_id;
return 1;
END IF;
END;
$function$

Related

Postgresql user-defined type and trigger

I have user defined type in Postgresql and table with this type:
CREATE TYPE public.hour_integer AS
(
q_1 integer,
q_2 integer,
q_3 integer,
q_4 integer
);
CREATE TABLE IF NOT EXISTS device_hours_data
(
device_hours_data_id serial,
date date,
h01 hour_integer ,
h02 hour_integer ,
h03 hour_integer ,
...
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
Now I need to create a trigger before insert with rule: if h01.q_1 is null then h01.q_1 = 0. How can I use correct syntax please ?
CREATE OR REPLACE FUNCTION public.device_hours_data_trigger()
RETURNS trigger
LANGUAGE 'plpgsql'
COST 100
VOLATILE NOT LEAKPROOF
AS $BODY$
DECLARE
v_hour character varying;
BEGIN
IF (NEW).h01.q_1 = null THEN
NEW.h01.q_1 = 0;
END IF;
...
RETURN NEW;
END;
$BODY$;
I am using something like:
NEW.h01.q_1 = 0; - syntax error,
(NEW).h01.q_1 = 0; - syntax error,
(NEW.h01).q_1 = 0; - syntax error....
Could you please help me?
Thanks
The only way I could get it to work is as suggested by #a_horse_with_no_name, something like:
CREATE OR REPLACE FUNCTION public.device_hours_data_trigger()
RETURNS trigger
LANGUAGE 'plpgsql'
COST 100
VOLATILE NOT LEAKPROOF
AS $BODY$
DECLARE
v_hour character varying;
new_hour hour_integer;
BEGIN
new_hour = NEW.h01;
IF new_hour.q_1 = null THEN
new_hour.q_1 = 0;
END IF;
...
NEW.h01 = new_hour;
RETURN NEW;
END;
$BODY$;

PostgreSQL - how to use equals for null in routine

I have a routine with 4 parameters passed in. Sometimes the last parameter "membership_type " is null but when I use equals it does not return records with null value, it does work if I use "is null" but looking for advice how to make sure both work in the same routine:
create or replace function fitnessone_master.get_location_cancellation_count(club_number double precision, date date, member_profile character varying, membership_type character varying) returns integer
language plpgsql
as $$
declare
member_count integer;
begin
return (select count(distinct a.agreement_number) as member_count
from fitnessone_master.cancelled_accounts a
where cancel_date = get_location_cancellation_count.date
and a.club_number = get_location_cancellation_count.club_number
and a.member_profile = get_location_cancellation_count.member_profile
and a.membership_type = get_location_cancellation_count.membership_type);
end;
$$;
Instead of using = x, which will never match NULL, you can use IS NOT DISTINCT FROM x:
create or replace function fitnessone_master.get_location_cancellation_count(club_number double precision, date date, member_profile character varying, membership_type character varying) returns integer
language plpgsql
as $$
declare
member_count integer;
begin
return (select count(distinct a.agreement_number) as member_count
from fitnessone_master.cancelled_accounts a
where cancel_date = get_location_cancellation_count.date
and a.club_number = get_location_cancellation_count.club_number
and a.member_profile = get_location_cancellation_count.member_profile
and a.membership_type is not distinct from get_location_cancellation_count.membership_type);
end;
$$;

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');

"Function does not exist" error when creating the function with more parameters

I have dropped a PL/pgSQL function and I try to recreate it with one more parameter (with default value). But I get a strange error:
ERROR: function vytvor_kod_sj(text, integer, integer) does not exist
SQL state: 42883
I would expect such an error while dropping or calling the function, not while creating it. I made sure that the error occurs exactly while trying to create it, not in any of the other functions or triggers I created from the same sql file.
I made a dummy function without the last parameter and it works now, but it is definitely not what I want - not only I don't need the function without the last parameter anymore, I usually call the function only with the first two or three parameter, so I need to drop it just after creating the new version of my function to avoid mismatches. Fortunately, there are no errors while doing this, but it is hardly optimal solution.
So does anyone know how to solve this mysterious problem?
I have PostgreSQL 9.3.4 on Windows 32; I use pgAdmin 1.18.1
My code:
CREATE OR REPLACE FUNCTION vytvor_kod_sj( _akce text, typ_sj integer,
podtyp integer DEFAULT 0, styl integer DEFAULT NULL )
RETURNS text AS $$
DECLARE
--styl integer;
_nazev_seq text;
_min integer;
_max integer;
_nazev text;
_soucasna integer;
BEGIN
IF styl IS NULL THEN
SELECT nomenklatura INTO styl FROM akce WHERE kod_akce = _akce;
END IF;
IF NOT EXISTS( SELECT id_nom FROM pro_nom_pravidlo_sj
WHERE id_nom = styl AND sj = typ_sj AND typ = podtyp ) THEN
IF podtyp = 0 OR NOT EXISTS( SELECT id_nom FROM pro_nom_pravidlo_sj
WHERE id_nom = styl AND sj = typ_sj AND typ = 0 ) THEN
RAISE NOTICE 'Pro daný typ stratigrafické jednotky není vytvořeno žádné pravidlo!';
RETURN NULL;
ELSE
podtyp := 0;
END IF;
END IF;
_nazev_seq := _akce || '_' || typ_sj || '_' || podtyp || '_seq';
IF NOT EXISTS (SELECT 0 FROM pg_class where relname = _nazev_seq ) THEN
SELECT min, max INTO _min, _max FROM pro_nom_pravidlo_sj
WHERE id_nom = styl AND sj = typ_sj AND typ = podtyp;
IF _max IS NOT NULL THEN
EXECUTE format('CREATE SEQUENCE %I MINVALUE %s MAXVALUE %s ', _nazev_seq, _min, _max);
ELSE
EXECUTE format('CREATE SEQUENCE %I MINVALUE %s ', _nazev_seq, _min);
END IF;
END IF;
--IF strict IS TRUE THEN
RETURN (
SELECT predpona FROM pro_nom_pravidlo_sj
WHERE id_nom = styl AND sj = typ_sj AND typ = podtyp
) || CAST(nextval(_nazev_seq) AS TEXT);
--END IF;
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER;
ALTER FUNCTION vytvor_kod_sj( text, integer, integer ) OWNER TO ins_daemon;
The old version had styl variable declared, not as a parameter, and there was no test whether it is null. Otherwise I didn't change anything.
I noticed the cause of the problem just after posting the question:
ALTER FUNCTION vytvor_kod_sj( text, integer, integer ) OWNER TO ins_daemon;
It tries to alter the old function.

Variable substitution in PL/pgSQL

I have a select statement that is generated dynamically based on the supplied parameter. The problem is that postgresql always says:
argument of WHERE must be type boolean, not type character varying no matter what the parameter is. Did I miss anything?
CREATE OR REPLACE FUNCTION getuid(name character varying) RETURNS integer AS $$
DECLARE
statement varchar;
uid integer;
BEGIN
IF ($1 = '') THEN
statement := 'TRUE';
statement := CAST(statement AS BOOLEAN);
ELSE
statement := 'users.keywords ILIKE''' || '%' || $1 || '%''';
END IF;
SELECT INTO uid id FROM users WHERE "statement";
RETURN uid;
END;
$$ LANGUAGE plpgsql
You need EXECUTE if you want to generate dynamic commands inside a function. You could also use two different sections:
CREATE OR REPLACE FUNCTION getuid(name character varying) RETURNS integer AS $$
DECLARE
statement varchar;
uid integer;
BEGIN
IF ($1 = '' OR $1 IS NULL) THEN -- section 1
SELECT id INTO uid FROM users;
ELSE -- section 2
SELECT id INTO uid FROM users WHERE users.keywords ILIKE '%' || $1 || '%';
END IF;
RETURN uid;
END;
$$ LANGUAGE plpgsql;
EXECUTE is a PL/pgSQL statement and not SQL statement. So you have to wrap your dynamic query into PL/pgSQL stored procedure.
Be careful about variable substitution and do not forget to use quote_literal() or quote_nullable() when building up you query.
Have look in documentation here: http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN