How do you pop an array in postgres? - postgresql

I'm wondering how to pop a value off from the top of an Array in postgresql using plpgsql?
CREATE FUNCTION pop_off(arr ANYARRAY) RETURNING ANYARRAY AS $$
BEGIN
-- return array with first element removed
END;
$$ LANGUAGE plpgsql;

Well, this wasn't as tough as I thought. Let's leverage the array_length method...
CREATE OR REPLACE FUNCTION pop_off(arr ANYARRAY) RETURNS ANYARRAY AS $$
BEGIN
RETURN (SELECT arr[2:array_length(arr,1)]);
END;
$$ LANGUAGE plpgsql;
There we go! Now let's test it...
LOG: statement: CREATE OR REPLACE FUNCTION pop_off(arr ANYARRAY) RETURNS ANYARRAY AS $$
BEGIN
RETURN (SELECT arr[2:array_length(arr,1)]);
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION
test_database=# SELECT pop_off('{1,2,3}'::int[]);
LOG: statement: SELECT pop_off('{1,2,3}'::int[]);
pop_off
---------
{2,3}
(1 row)

Related

Select Statement using Stored Procedure

May I ask on how to call a method when the content of the stored procedure is about select statement? (Using postgreSQL)
CREATE OR REPLACE PROCEDURE select_table(table_name VARCHAR(255))
language plpgsql
as $$
BEGIN
EXECUTE('SELECT * FROM' || ' ' || quote_ident(table_name));
END $$;
CALL select_table('employee_table');
EDITED(USING FUNCTION)
CREATE OR REPLACE FUNCTION select_table(table_name VARCHAR(255))
language plpgsql
as $$
BEGIN
SELECT * FROM table_name
RETURN table_name;
END $$;
In PostgreSQL procedures doesn't execute any select statements and doesn't have return.
For returning data you can use functions. But functions also cannot return different structural data, examples:
CREATE OR REPLACE FUNCTION fr_test()
RETURNS TABLE(id integer, bookname character varying)
LANGUAGE plpgsql
AS $function$
begin
return QUERY
SELECT tb.id, tb.bookname from rbac.books tb;
end;
$function$
;
or
CREATE OR REPLACE FUNCTION fr_test()
RETURNS setof public.books
LANGUAGE plpgsql
AS $function$
begin
return QUERY
SELECT * from public.books;
end;
$function$
;
But for returning difference tables you can do it using procedures and using out refcursor, like as in Oracle. For example:
create or replace procedure pr_test(OUT r1 refcursor)
as $$
begin
open r1 for
select * from public.books;
end;
$$ language plpgsql;

Declare type of setof bigint in plpgsql function and assign into from select union

The following code currently works on PostgreSQL 13.3 (via Supabase.io). Both functions get_owned_base_ids and get_bases_editable have return type of setof bigint:
CREATE FUNCTION get_owned_base_ids()
returns setof bigint
stable
language sql
as $$
select id
from bases
where bases.owner_user_id = auth.uid();
$$;
-- CREATE FUNCTION get_bases_editable()
-- returns setof bigint
-- ... similar to get_owned_base_ids()
-- $$;
CREATE FUNCTION xyz (base_id bigint)
returns int
language plpgsql
as $$
BEGIN
IF base_id not in (select get_owned_base_ids() UNION select get_bases_editable()) THEN
-- note: actual function logic is simplified for this question
return 1;
END IF;
return 0;
END;
$$;
Is it possible to define a setof bigint and assign that from the select union? Something like this:
CREATE FUNCTION xyz (base_id bigint)
returns int
language plpgsql
as $$
DECLARE
allowed_base_ids bigint; -- needs to be a setof
BEGIN
select into allowed_base_ids get_owned_base_ids() UNION select get_bases_editable();
IF kv.base_id not in allowed_base_ids THEN
-- note: actual function logic is simplified for this question
return 1;
END IF;
return 0;
END;
$$;
It usually does not make much sense and use much memory of the result set is large, but you can use an array:
DECLARE
allowed_base_ids bigint[];
BEGIN
allowed_base_ids := array(SELECT * FROM get_owned_base_ids()
UNION ALL
SELECT * FROM get_bases_editable());
IF kv.base_id <> ALL (allowed_base_ids) THEN
...
END IF;
END;

PostgreSQL - Function that returns labels of any ENUM

I am trying to write a "generic" function that will return labels of any enum (in any schema)...
But I am not having much luck because I am not sure what should argument type be...
The goal would be to be able to call function like this
SELECT common.get_enum_labels('public.rainbow_colors');
SELECT common.get_enum_labels('audit.user_actions');
This is what I have so
CREATE OR REPLACE FUNCTION common.get_enum_labels(enum_name regtype)
RETURNS SETOF text AS
$$
BEGIN
EXECUTE format('SELECT unnest(enum_range(NULL::%s))::text AS enum_labels ORDER BY 1', enum_name);
END;
$$
LANGUAGE plpgsql
STABLE
PARALLEL SAFE
;
Any tips would be appreciated
The argument type should be regtype, do not forget to return something from the function
CREATE OR REPLACE FUNCTION get_enum_labels(enum_name regtype)
RETURNS SETOF text AS
$$
BEGIN
RETURN QUERY
EXECUTE format('SELECT unnest(enum_range(NULL::%s))::text ORDER BY 1', enum_name);
END;
$$
LANGUAGE plpgsql
create or replace function get_enum_labels(enum_name regtype)
returns setof text language sql stable
as $$
select enumlabel::text
from pg_enum
where enumtypid = enum_name
order by enumsortorder
$$;

PostgreSQL: How to recognize data type?

How to recognize the data type of anyelement inside function?
CREATE OR REPLACE FUNCTION test1(par1 int,**par2 anyelement**)
RETURNS BOOL
AS $$
DECLARE rc bool := true;
BEGIN
-- ?
RETURN rc;
END;
$$
LANGUAGE plpgsql;
Use pg_typeof(any):
create or replace function test(par anyelement)
returns text language plpgsql as $$
begin
return pg_typeof(par)::text;
end $$;
select test(100::int), test('2012-12-12'::date);
test | test
---------+------
integer | date
(1 row)

Return ResultSet in pgsql function

I have the function below...
CREATE OR REPLACE FUNCTION class_listing(var_sem integer, var_sy character) RETURNS SETOF RECORD AS
DECLARE
current_offering record;
BEGIN
SELECT subcode, offerno INTO current_offering FROM offering WHERE SY=var_sem AND SEM=var_sy;
END;
How to return current_offering as resultset?
You can use a SQL or PLpgSQL functions. Using anonymous records as returning type is not practical (mainly it is not friendly, when you write queries). Use RETURNS TABLE or OUT parameters instead.
CREATE OR REPLACE FUNCTION class_listing(var_sem integer, var_sy varchar)
RETURNS TABLE (subcode varchar, offerno int) AS $$
BEGIN
RETURN QUERY SELECT o.subcode, o.offerno
FROM offering
WHERE SY=var_sem AND SEM=var_sy;
END;
$$ LANGUAGE plpgsql;
or SQL language
CREATE OR REPLACE FUNCTION class_listing(var_sem integer, var_sy varchar)
RETURNS TABLE (subcode varchar, offerno int) AS $$
SELECT o.subcode, o.offerno
FROM offering
WHERE SY=$1 AND SEM=$2;
$$ LANGUAGE sql;
Attentions - query based functions works (with small exception) as optimizer barrier. So be careful when you use it in complex queries.
For completeness - your example can be written as:
CREATE OR REPLACE FUNCTION class_listing(var_sem integer, var_sy varchar)
RETURNS SETOF RECORD AS $$
DECLARE current_offering record;
BEGIN
FOR current_offering IN
SELECT o.subcode, o.offerno
FROM offering
WHERE SY=var_sem AND SEM=var_sy;
LOOP
RETURN NEXT current_offering;
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
But this form is deprecated now