Facing issue while calling a stored procedure with if else condition in redshift - amazon-redshift

I created the stored procedure in redshift. Below is the code for that.
create or replace procedure sp4(f1 IN int)
as
$$
begin
IF f1==0 then
CREATE TABLE myetl(a int, b varchar);
ELSE
insert into new_tbl(id) values(47);
END IF;
end;
$$ LANGUAGE plpgsql;
While calling the stored procedure I am getting the error like this
call sp4(0)
ERROR: operator does not exist: integer == integer Hint: No operator matches the given name and argument type(s). You may need to add explicit type casts. Where: SQL statement "SELECT $1 ==0" PL/pgSQL function "sp4" line 2 at if

Your comparison should be IF f0 = 0 THEN, with single equal signs. See the Redshift PLpgSQL documentation

Related

Postgresql - Stored Procedure that returns a table result set

Im new to PostgreSQL v.13 and want to create a Stored Procedure that will receive an integer value and then return the results from a table.
I have this:
create or replace procedure public.sp_message_template_get(
templateid int
) language plpgsql AS $$
begin
-- subtracting the amount from the sender's account
select * from public.message_template;
--commit;
end;
$$
Then I try to call it by using:
call public.sp_message_template_get(1);
And I get the following error:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function sp_message_template_get(integer) line 6 at SQL statement
SQL state: 42601
Any clue?
Thanks
Create a sql function.
create or replace function message_template_get(templateid integer)
returns setof message_template language sql as
$$
-- subtracting the amount from the sender's account (sql query)
select * from public.message_template;
$$;
If there is a reason to use plpgsql language then use return query.
create or replace function message_template_get(templateid integer)
returns setof message_template language plpgsql as
$$
begin
-- subtracting the amount from the sender's account
return query select * from public.message_template;
-- maybe other statements here
end;
$$;
Please note that commit is not necessary and illegal in a function body. More than one return query or return next statements are possible.

Invalid input syntax for type integer: "(2,2)" with composite data type while executing function

begin;
create type public.ltree as (a int, b int);
create table public.parent_tree(parent_id int,l_tree ltree);
insert into public.parent_tree values(1,(2,2)),(2,(1,2)),(3, (1,28));
commit;
Trying to replicate the solution in this answer:
Format specifier for integer variables in format() for EXECUTE?
For a function with composite type:
CREATE OR REPLACE FUNCTION public.get_parent_ltree
(_parent_id int, tbl_name regclass , OUT _l_tree ltree)
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('SELECT l_tree FROM %s WHERE parent_id = $1', tbl_name)
INTO _l_tree
USING _parent_id;
END
$func$;
The effective query executed:
select l_tree from parent_tree where parent_id = 1;
Executing the function:
select get_parent_ltree(1,'parent_tree');
select get_parent_ltree(1,'public.parent_tree');
I get this error:
ERROR: invalid input syntax for type integer: "(2,2)"
CONTEXT: PL/pgSQL function get_parent_ltree(integer,regclass) line 3 at EXECUTE
Context of line 3:
The output parameter _l_tree is a "row variable". (A composite type is treated as row variable.) SELECT INTO assigns fields of a row variable one-by-one. The manual:
The optional target is a record variable, a row variable, or a comma-separated list of simple variables and record/row fields, [...]
So, currently (pg 14), a row or record variables must stand alone as target. Or as the according Postgres error message would put it:
ERROR: record variable cannot be part of multiple-item INTO list
This works:
CREATE OR REPLACE FUNCTION public.get_parent_ltree (IN _parent_id int
, IN _tbl_name regclass
, OUT _l_tree ltree)
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('SELECT (l_tree).* FROM %s WHERE parent_id = $1', _tbl_name)
INTO _l_tree
USING _parent_id;
END
$func$;
Or this:
CREATE OR REPLACE FUNCTION public.get_parent_ltree2 (IN _parent_id int
, IN _tbl_name regclass
, OUT _l_tree ltree)
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('SELECT (l_tree).a, (l_tree).b FROM %s WHERE parent_id = $1', _tbl_name)
INTO _l_tree.a, _l_tree.b
USING _parent_id;
END
$func$;
db<>fiddle here
I agree that this is rather tricky. One might expect that a composite field is treated as a single field (like a simple type). But that's currently not so in PL/pgSQL assignments.
A related quote from the manual about composite types:
A composite type represents the structure of a row or record; it is
essentially just a list of field names and their data types.
PostgreSQL allows composite types to be used in many of the same ways that simple types can be used.
Bold emphasis mine.
Many. Not all.
Related:
Use of custom return types in a FOR loop in plpgsql
PostgreSQL: ERROR: 42601: a column definition list is required for functions returning "record"
Aside: Consider the additional module ltree instead of "growing your own". And if you continue working with your own composite type, consider a different name to avoid confusion / conflict with that module.
It looks like a Postgres bug but Erwin clarifies the issue in the adjacent answer. One of the natural workarounds is to use an auxiliary text variable in the way like this:
create or replace function get_parent_ltree(_parent_id int, tbl_name regclass)
returns ltree language plpgsql as
$func$
declare
rslt text;
begin
execute format('select l_tree from %s where parent_id = $1', tbl_name)
into rslt
using _parent_id;
return rslt::ltree;
end
$func$;

Returning from a function with OUT parameter

I have an error, but I don't know what the problem is.
I want execute a function and return a value from a column filled in by the column default, a sequence - the equivalent of currval(sequence).
I use:
PostgreSQL 9.0
pgAdmin III
CREATE OR REPLACE FUNCTION name_function(in param_1 character varying
, out param_2 bigint)
AS
$$
BEGIN
INSERT INTO table (collumn_seq,param_1) VALUES (DEFAULT,param_1)
returning collumn_seq;
--where:collumn_seq reference a collumn serial..
END;
$$
LANGUAGE plpgsql VOLATILE;
I can create the function without error but when trying to execute, the following error is returned:
SELECT name_function('GHGHGH');
ERROR: The query has no destination for result data
It would work like this:
CREATE OR REPLACE FUNCTION name_function(param_1 varchar
, OUT param_2 bigint)
LANGUAGE plpgsql AS
$func$
BEGIN
INSERT INTO table (collumn_seq, param_1) -- "param_1" also the column name?
VALUES (DEFAULT, param_1)
RETURNING collumn_seq
INTO param2;
END
$func$;
Normally, you would add a RETURN statement, but with OUT parameters, this is optional.
Refer to the manual for more details:
Returning from a function
Executing a Query with a Single-row Result
The simple case can be covered with a plain SQL function.
And you can omit the target column that shall get its DEFAULT value.
And you can just as well use a RETURNS clause in this case:
CREATE OR REPLACE FUNCTION name_function(param_1 varchar)
RETURNS bigint
LANGUAGE sql AS
$func$
INSERT INTO table (param_1) -- "param_1" also the column name?
VALUES (param_1)
RETURNING collumn_seq;
$func$;

PL/pgSQL - insert multiple rows, returning the ids in a resultset

I am using PostgreSQL 8.4. My goal is to insert multiple rows with the help of PL/pgSQL and return the id-s of the inserted records back in a recordset.
At first I tried to do it in a single row, using the following code for my permission_create(..) function:
CREATE FUNCTION permission_create(
IN method permission.permission_method % TYPE,
IN resource permission.permission_resource % TYPE
)
RETURNS TABLE(id permission.permission_id % TYPE)
AS
$BODY$
BEGIN
RETURN QUERY
WITH inserted_permission AS (
INSERT INTO permission (permission_id, permission_method, permission_resource) VALUES (DEFAULT, method, resource)
RETURNING permission_id
)
SELECT
inserted_permission.permission_id AS id
FROM inserted_permission;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
However, I got the following error message:
[2013-07-04 17:38:01] [00000] type reference permission.permission_method%TYPE converted to character varying
[2013-07-04 17:38:01] [00000] type reference permission.permission_resource%TYPE converted to character varying
[2013-07-04 17:38:01] [00000] type reference permission.permission_id%TYPE converted to integer
[2013-07-04 17:38:01] [00000] type reference permission.permission_id%TYPE converted to integer
[2013-07-04 17:38:01] [42601] ERROR: syntax error at or near "INSERT"
Where: SQL statement in PL/PgSQL function "permission_create" near line 9
How should I fix this? Is there a way to do this in multiple lines?
Solution:
CREATE FUNCTION permission_create(
IN method permission.permission_method % TYPE,
IN resource permission.permission_resource % TYPE
)
RETURNS TABLE (id INT)
AS
$BODY$
BEGIN
RETURN QUERY
INSERT INTO permission (permission_id, permission_method, permission_resource)
VALUES (DEFAULT, method, resource)
RETURNING permission_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Updateable CTE is supported from PostgreSQL 9.1.
you don't need use CTE (in your case)
postgres=# CREATE OR REPLACE FUNCTION fx()
RETURNS SETOF int AS $$
BEGIN
RETURN QUERY INSERT INTO taba(a) VALUES(1),(2)
RETURNING *;
RETURN;
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION
postgres=# select * from fx();
fx
----
1
2
(2 rows)

How to use EXECUTE FORMAT ... USING in postgres function

CREATE OR REPLACE FUNCTION dummytest_insert_trigger()
RETURNS trigger AS
$BODY$
DECLARE
v_partition_name VARCHAR(32);
BEGIN
IF NEW.datetime IS NOT NULL THEN
v_partition_name := 'dummyTest';
EXECUTE format('INSERT INTO %I VALUES ($1,$2)',v_partition_name)using NEW.id,NEW.datetime;
END IF;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION dummytest_insert_trigger()
OWNER TO postgres;
I'm trying to insert using
insert into dummyTest values(1,'2013-01-01 00:00:00+05:30');
But it's showing error as
ERROR: function format(unknown) does not exist
SQL state: 42883
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Context: PL/pgSQL function "dummytest_insert_trigger" line 8 at EXECUTE statement
I'm unable get the error.
Your function could look like this in Postgres 9.0 or later:
CREATE OR REPLACE FUNCTION dummytest_insert_trigger()
RETURNS trigger AS
$func$
DECLARE
v_partition_name text := quote_ident('dummyTest'); -- assign at declaration
BEGIN
IF NEW.datetime IS NOT NULL THEN
EXECUTE
'INSERT INTO ' || v_partition_name || ' VALUES ($1,$2)'
USING NEW.id, NEW.datetime;
END IF;
RETURN NULL; -- You sure about this?
END
$func$ LANGUAGE plpgsql;
About RETURN NULL:
To ignore result in BEFORE TRIGGER of PostgreSQL?
I would advice not to use mixed case identifiers. With format( .. %I ..) or quote_ident(), you'd get a table named "dummyTest", which you'll have to double quote for the rest of its existence. Related:
Are PostgreSQL column names case-sensitive?
Use lower case instead:
quote_ident('dummytest')
There is really no point in using dynamic SQL with EXECUTE as long as you have a static table name. But that's probably just the simplified example?
You need explicit cast to text:
EXECUTE format('INSERT INTO %I VALUES ($1,$2)'::text ,v_partition_name) using NEW.id,NEW.datetime;