We have a function written in pl/sql(oracle) as below:
CREATE OR REPLACE PROCEDURE folder_cycle_check (folder_key IN NUMBER, new_parent_folder_key IN NUMBER) IS
parent_of_parent NUMBER;
ILLEGAL_CYCLE EXCEPTION;
CURSOR parent_c IS
SELECT parent_folder_key FROM folder
WHERE folder_key = new_parent_folder_key;
BEGIN
IF folder_key = new_parent_folder_key THEN
RAISE ILLEGAL_CYCLE;
END IF;
FOR parent_rec IN parent_c LOOP
BEGIN folder_cycle_check(folder_key, parent_rec.parent_folder_key); END;
END LOOP;
END;
Now, i have to rewrite this same procedure in pl/pgsql(PostgreSQL) to achieve similar functionality. Please help me and send that pl/pgsql function.
Edit (formatted code from the comments)
CREATE OR REPLACE FUNCTION folder_cycle_check(IN folder_key INTEGER, IN new_parent_folder_key INTEGER)
RETURNS VOID
AS $procedure$
DECLARE parent_of_parent INTEGER;
PARENT_C CURSOR FOR
SELECT parent_folder_key
FROM folder
WHERE folder_key = new_parent_folder_key;
BEGIN
IF folder_key = new_parent_folder_key THEN
RAISE EXCEPTION 'ILLEGAL_CYCLE';
END IF
FOR parent_rec IN (SELECT parent_folder_key FROM folder WHERE folder_key = new_parent_folder_key) LOOP
PERFORM folder_cycle_check(folder_key,parent_rec.parent_folder_key);
END LOOP;
RETURN;
END;
$procedure$
LANGUAGE plpgsql;
This should work:
CREATE OR REPLACE FUNCTION folder_cycle_check (p_folder_key INT4, p_new_parent_folder_key INT4) RETURNS VOID AS $$
DECLARE
v_parent_rec RECORD;
BEGIN
IF folder_key = new_parent_folder_key THEN
RAISE EXCEPTION 'ILLEGAL_CYCLE';
END IF;
FOR v_parent_rec IN SELECT parent_folder_key FROM folder WHERE folder_key = p_new_parent_folder_key LOOP
PERFORM folder_cycle_check(folder_key, v_parent_rec.parent_folder_key)
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
Related
HiAll,
when I am running the below function getting the error as
ERROR: record "v_preorderrec" is not assigned yet.
Even I initialized v_preorderrec:=null;
Please help me.
CREATE OR REPLACE FUNCTION order_f1(p_order_num text)
RETURNS void
LANGUAGE plpgsql
AS $function$
DECLARE
c_order CURSOR FOR
SELECT od.itemno,
it.item_cost,
it.item_code
FROM orderdtls od
LEFT OUTER JOIN itemdtls it ON (od.itemno = it.itemno)
WHERE od.order_num = p_order_num
v_orderrec RECORD;
v_preorderrec RECORD;
BEGIN
v_preorderrec:=null;
open c_order;
loop
fetch c_order
into v_orderrec;
IF NOT FOUND THEN EXIT; END IF;
if coalesce(v_preorderrec.itemno::text, '') = '' or
v_preorderrec.itemno !=
v_orderrec.itemno then
perform modorder(v_orderrec.itemno);
end if;
v_preorderrec := v_orderrec;
end loop;
close c_order;
END;
$function$
;
Thanks in advance.
I am building a procedure, which is called by a trigger, after an insert, and an error is occurring when I use a select statement in its body.
When I do NOT use select, to get a value, there is NO error when the trigger calls this procedure:
BEGIN;
CREATE OR REPLACE FUNCTION calc_virtual()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
_virtual RECORD;
_value_calc DECIMAL;
_complet BOOLEAN;
BEGIN
_value_calc = 0
FOR _virtual IN SELECT value
FROM virtual
WHERE id = NEW.id
LOOP
_value_calc = _value_calc-(value * 1.5);
END LOOP;
INSERT INTO appointment (value) VALUES (_value_calc);
RETURN NEW;
END;
$function$;
COMMIT;
When I use select, to get a value, an error occurs when the trigger calls this procedure:
BEGIN;
CREATE OR REPLACE FUNCTION calc_virtual()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
_virtual RECORD;
_value_calc DECIMAL;
_complet BOOLEAN;
BEGIN
FOR _virtual IN SELECT value
FROM virtual
WHERE id = NEW.id
LOOP
_value_calc = 0;
_complet = TRUE;
SELECT value_active
FROM appointment_virtual
WHERE name = _virtual.name;
IF FOUND THEN
_value_calc = _value_calc-(value_active * 1.5);
ELSE
_complet = False;
END IF;
END LOOP;
IF _complet THEN
INSERT INTO appointment (value) VALUES (_value_calc);
END IF;
RETURN NEW;
END;
$function$;
COMMIT;
Thanks por any help!
You have to use SELECT ... INTO in PL/pgSQL. No variable value_active will magically be created.
SELECT value_active INTO _active
FROM appointment_virtual
WHERE name = _virtual.name;
IF FOUND THEN
_value_calc = _value_calc-(_active * 1.5);
...
You have to declare _active in the DECLARE section.
I'm new to PostgreSQL. I have experience in oracle. In oracle , to find the exact error, I use code 'dbms_output.put_line(sqlerrm)' . Here I have a postgresql function returning an integer value
CREATE OR REPLACE FUNCTION public.fn_sqltest(
p_id integer)
RETURNS integer
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
Declare
n integer;
begin
select off_id into n from office
where per_id=p_id;
return n ;
exception when others then
return -1;
end;
$BODY$;
ALTER FUNCTION public.fn_sqltest(character varying)
OWNER TO postgres;
I call this function as below
DO $$
DECLARE
ae integer;
BEGIN
ae:=fn_sqltest(10);
RAISE NOTICE 'exception: % % ', sqlstate , sqlerrm ;
RAISE NOTICE 'Return value is: % ', ae;
END $$;
and I get the error
ERROR: column "sqlstate" does not exist
How can I show the exact error message like sqlerrm in oracle.
I updated the function and wrote a code in function exception section
CREATE OR REPLACE FUNCTION public.fn_sqltest(
p_id integer)
RETURNS integer
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
Declare
n integer;
text_var1 text;
text_var2 text;
text_var3 text;
begin
select off_id into n from office
where per_id=p_id;
return n ;
exception when others then
GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
text_var2 = PG_EXCEPTION_DETAIL,
text_var3 = PG_EXCEPTION_HINT;
RAISE NOTICE 'Return value is: % % %',text_var1 , text_var2, text_var3;
return -1;
end;
$BODY$;
ALTER FUNCTION public.fn_sqltest(character varying)
OWNER TO postgres;
Another method is by changing the return type. I changed the return type to text and rewrite the exception section code as below
return sqlerrm;
Unlike PL/SQL, in PL/pgSQL SQLSTATE and SQLERRM are not defined outside an exception handler. See the documentation, section "Obtaining Information About An Error".
This also means that you can't get SQLSTATE and SQLERRM of a successful operation, unlike PL/SQL.
So, if you want to use these special variables outside an exception handler, you have to store them in variables.
I don't know how would you like to return them from the function. I can demonstrate this idea inside your function code:
CREATE OR REPLACE FUNCTION public.fn_sqltest(
p_id integer)
RETURNS integer
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
Declare
n integer;
v_sqlerrm text;
v_sqlstate text;
begin
begin
select off_id into n from office
where per_id=p_id;
return n ;
exception when others then
v_sqlerrm := sqlerrm;
v_sqlstate := sqlstate;
end;
RAISE NOTICE 'exception: % % ', v_sqlstate , v_sqlerrm ;
return -1;
end;
$BODY$;
I know this is old but just for the record: The easiest way to output the state and message of error is to raise them from within the exception clause. You don't need to declare extra variables.
CREATE OR REPLACE FUNCTION fn_sqltest(p_id integer)
RETURNS integer
AS $$
DECLARE
n integer;
BEGIN
SELECT off_id
INTO n
FROM office
WHERE per_id = p_id;
RETURN n;
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'exception: % - %', SQLSTATE, SQLERRM;
RETURN -1;
END;
$$ LANGUAGE plpgsql;
I am trying to make the following function working:
CREATE OR REPLACE FUNCTION validate_count(devices TEXT[], campaign_id INTEGER) RETURNS void AS $$
DECLARE
devices_array TEXT[] := devices;
devices_count INTEGER := array_length(devices, 1);
row_id INTEGER := campaign_id;
BEGIN
FOR device IN unnest(devices_array) LOOP
IF my_count('my_table', device, row_id) != 1;
RAISE EXCEPTION 'invalid_count %', row_id
ENDIF
END LOOP;
END
$$ LANGUAGE plpgsql;
my_count is a working function which returns INTEGER.
The definition fails with the error:
ERROR: syntax error at or near "unnest"
LINE 7: FOR device IN unnest(devices_array) LOOP
Could you spot the issue? Thanks!
I am planning to call the function as follows:
select validate_count('{foo, bar}', 1)
Use a FOREACH loop:
CREATE OR REPLACE FUNCTION validate_count(devices TEXT[], campaign_id INTEGER)
RETURNS void
AS
$$
DECLARE
device text;
devices_count INTEGER := array_length(devices, 1);
BEGIN
FOREACH device IN ARRAY devices LOOP
IF my_count('my_table', device, campaign_id) <> 1 then
RAISE EXCEPTION 'invalid_count %', campaign_id;
END IF;
END LOOP;
END
$$
LANGUAGE plpgsql;
A few things need to be fixed to make this valid.
The FOR loop needs SELECT before the unnest, i.e.:
FOR device IN SELECT unnest(devices_array) LOOP
You need to declare device up top, for example:
DECLARE device RECORD;
The IF statement needs a THEN instead of a ;, i.e.:
IF my_count('my_table', device, row_id) != 1 THEN
The RAISE EXCEPTION statement needs a semicolon at the end of the line, i.e.:
RAISE EXCEPTION 'invalid_count %', row_id;
The END for the IF statement should be END IF;.
The END for the LOOP statement should be END LOOP;.
Here's the net result:
CREATE OR REPLACE FUNCTION validate_count(devices TEXT[], campaign_id INTEGER) RETURNS void AS $$
DECLARE
devices_array TEXT[] := devices;
devices_count INTEGER := array_length(devices, 1);
row_id INTEGER := campaign_id;
device RECORD;
BEGIN
FOR device IN SELECT unnest(devices_array) LOOP
IF my_count('my_table', device, row_id) != 1 THEN
RAISE EXCEPTION 'invalid_count %', row_id;
END IF;
END LOOP;
END
$$ LANGUAGE plpgsql;
I have the following trigger function:
CREATE OR REPLACE FUNCTION update_modelname_function()
RETURNS trigger AS
$BODY$
BEGIN
IF tg_op = 'INSERT' THEN
new.model_name := upper(new.model_name);
RETURN new;
END IF;
IF tg_op = 'UPDATE' THEN
old.model_name := upper(old.model_name);
RETURN new;
END IF;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
What I'm trying to achieve is for the value of the column model_name to always be uppercased when it's persisted in the table. However nothing seems to happen. Any ideas?
You accidentally updated OLD instead of NEW. Try:
CREATE OR REPLACE FUNCTION update_modelname_function()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
IF TG_OP = 'INSERT' THEN
NEW.model_name := upper(NEW.model_name);
RETURN NEW;
ELSIF TG_OP = 'UPDATE' THEN
NEW.model_name := upper(NEW.model_name); -- !
RETURN NEW;
END IF;
END
$func$;
If the example shows the whole code, and the actual trigger(s) only fires on INSERT and/or UPDATE, further simplify:
CREATE OR REPLACE FUNCTION update_modelname_function()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
NEW.model_name := upper(NEW.model_name);
RETURN NEW;
END
$func$;