How to pass ENUM variable as input for POSTGRESQL functions - postgresql

I have a function in MySQL which works fine:
CREATE PROCEDURE `Accounts_Active`(IN_DeptName VARCHAR(255), IN_Src ENUM('TRAINING','ELZA'))
BEGIN
END$$
DELIMITER ;
But when converted to PostgreSQL:
CREATE or replace FUNCTION Accounts_Active(IN_DeptName VARCHAR(255), IN_Src ENUM('TRAINING','ELZA'))
RETURNS void
AS
$$
BEGIN
RAISE INFO ' ';
END;
$$ LANGUAGE plpgsql;
The following error occurs:
ERROR: type enum does not exist
SQL state: 42704
Any guidance on how I can fix this error would be appreciated.

Create an enum data type:
CREATE TYPE atype AS ENUM ('TRAINING', 'ELZA');
Then you can use it as function parameter:
CREATE FUNCTION Accounts_Active(
IN_DeptName text,
IN_Src atype
) RETURNS void
...
When using enums, remember that you can add values to such a data type, but never again remove them. Often you will be better of using a string data type like text, but of course then you have to write code that checks the input for validity.

Related

how do I pass a user defined type variable to a function as a parameter?

I want to pass a user defined type parameter to a PLPGSQL function, but I am getting this error at runtime:
dev=# select process_shapes();
ERROR: invalid input syntax for integer: "(,,7)"
CONTEXT: PL/pgSQL function process_shapes() line 9 at SQL statement
dev=#
For some reason, the parameters are not passed correctly and I have no idea why it doesn't work.
My functions are:
CREATE OR REPLACE FUNCTION join_shapes(first_shape shape_t,second_shape shape_t,OUT new_shape shape_t)
AS $$
DECLARE
BEGIN -- simplified join_shape()s function
new_shape.num_lines:=first_shape.num_lines+second_shape.num_lines;
END;
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION process_shapes()
RETURNS void AS $$
DECLARE
rectangle shape_t;
triangle shape_t;
produced_shape shape_t;
BEGIN
rectangle.num_lines:=4;
triangle.num_lines:=3;
SELECT join_shapes(rectangle,triangle) INTO produced_shape;
RAISE NOTICE 'produced shape = %s',produced_shape;
END;
$$ LANGUAGE PLPGSQL;
Type definition:
CREATE TYPE shape_t AS (
shape_id integer,
shape_name varchar,
num_lines integer
);
Postgres version: 9.6.1
When the target of a SELECT ... INTO statement is of a composite type, it will assign each of the columns returned by the SELECT to a different field in the target.
However, SELECT join_shapes(rectangle,triangle) returns a single column of type shape_t, and it's trying to cram the whole thing into the first column of the target, i.e. produced_shape.shape_id (hence the error message about a failed integer conversion).
Instead, you need a SELECT statement which returns three columns. Just replace
SELECT join_shapes(rectangle,triangle)
with
SELECT * FROM join_shapes(rectangle,triangle)
Alternatively, you could use
produced_shape := (SELECT join_shapes(rectangle,triangle));
which performs a single assignment, rather than trying to assign the target fields individually.
For other people whom want to pass composite types to functions:
create type pref_public.create_test_row_input as (
name text
);
create or replace function pref_public.create_test_row(test_row pref_public.create_test_row_input) returns pref_public.test_rows as $$
insert into pref_public.test_rows (name)
values
(test_row.name)
returning *;
$$ language sql strict security definer;
grant execute on function pref_public.create_test_row to pref_user;
You'll need to use row()
select * from pref_public.create_test_row(row('new row'));
More info here

Pass UUID value as a parameter to the function

I have the table with some columns:
--table
create table testz
(
ID uuid,
name text
);
Note: I want to insert ID values by passing as a parameter to the function. Because I am generating the ID value
in the front end by using uuid_generate_v4(). So I need to pass the generated value to the function to insert
into the table
My bad try:
--function
CREATE OR REPLACE FUNCTION testz
(
p_id varchar(50),
p_name text
)
RETURNS VOID AS
$BODY$
BEGIN
INSERT INTO testz values(p_id,p_name);
END;
$BODY$
LANGUAGE PLPGSQL;
--EXECUTE FUNCTION
SELECT testz('24f9aa53-e15c-4813-8ec3-ede1495e05f1','Abc');
Getting an error:
ERROR: column "id" is of type uuid but expression is of type character varying
LINE 1: INSERT INTO testz values(p_id,p_name)
You need a simple cast to make sure PostgreSQL understands, what you want to insert:
INSERT INTO testz values(p_id::uuid, p_name); -- or: CAST(p_id AS uuid)
Or (preferably) you need a function, with exact parameter types, like:
CREATE OR REPLACE FUNCTION testz(p_id uuid, p_name text)
RETURNS VOID AS
$BODY$
BEGIN
INSERT INTO testz values(p_id, p_name);
END;
$BODY$
LANGUAGE PLPGSQL;
With this, a cast may be needed at the calling side (but PostgreSQL usually do better automatic casts with function arguments than inside INSERT statements).
SQLFiddle
If your function is that simple, you can use SQL functions too:
CREATE OR REPLACE FUNCTION testz(uuid, text) RETURNS VOID
LANGUAGE SQL AS 'INSERT INTO testz values($1, $2)';

How to cast string value to enum

I have a table with an enum type in it, and I created a function to add data to that table. I want that function to be generous in what to accept, so I take a text as the enum type and want to cast it later.
This is the enum:
CREATE TYPE public.enum_log_priority AS ENUM (
'critical','error','warning','notice','debug'
);
And this is the function:
CREATE OR REPLACE FUNCTION public.log_write(
_message text,
_priority text
) RETURNS integer AS
$body$
BEGIN
_priority = lower(_priority);
INSERT INTO log (message, priority) VALUES (_message, _priority);
RETURN 0;
END
$body$
LANGUAGE 'plpgsql';
I know this doesn't work:
ERROR: column "priority" is of type enum_log_priority but expression is of type text
but how can I do this?
Use syntax like below during insertion
'critical'::enum_log_priority
Please see some link as well
http://www.postgresql.org/docs/9.1/static/datatype-enum.html
Inserting into custom SQL types with prepared statements in java
java enum and postgresql enum
change your function like this:
CREATE OR REPLACE FUNCTION public.log_write(
_message text,
_priority text
) RETURNS integer AS
$body$
BEGIN
_priority = lower(_priority);
INSERT INTO log (message, priority) VALUES (_message, _priority::enum_log_priority);
RETURN 0;
END
$body$
LANGUAGE 'plpgsql';
| sql fiddle demo |
Postgres supports also the cast function:
cast(priority AS enum_log_priority);
Consider that sometimes (for example in Prisma raw queries) you need to put the enum type inside quotations.
'critical'::"enum_log_priority"

Using ENUM types in functions

I have a function defined as follows:
CREATE OR REPLACE FUNCTION public.somefcn(
_somevar enum_my_type
)
RETURNS integer AS
$body$
DECLARE
ret_id INTEGER
BEGIN
INSERT INTO mytable(somevar) VALUES (_somevar) RETURNING id INTO ret_id;
RETURN ret_id;
END;
$body$
LANGUAGE 'plpgsql'
When I call this like this
SELECT somefcn('validenumitem');
I get this error:
ERROR: column "somevar" is of type enum_my_type but expression is of type text
How should I update my function or call to make it work?
Found it. I had another, incorrect function as
CREATE OR REPLACE FUNCTION public.somefcn(
_somevar text
)
...
Apparently, PostgreSQL took that one, because it fits better.

PLPython & CAST composite data type in Postgresql

I am writing a stored procedure in PlPython with a user defined type. I know Plpython does not support user defined types, so, I have created a CAST for the user defined type. Still I keep getting an error when I call plpy.prepare. I am not sure if I am using the CAST incorrectly - the example code is below:
#User Defined Type - person
CREATE TYPE person As( name character varying(50), state character(2));
#Table definition using 'person'
CREATE TABLE manager As(id integer, mgr person)
#CAST for person
CREATE OR REPLACE FUNCTION person_to_text(person) RETURNS text AS 'SELECT ROW($1.*)::text' LANGUAGE SQL;
CREATE CAST (cv_person as text) WITH FUNCTION person_to_text(person)
#PlPython procedure
CREATE OR REPLACE FUNCTION load_portfolio_assoc (name text, state text) RETURNS integer AS $$
mgr_str ="('"+name+"','"+state+"')"
insert_qry = 'Insert into manager (mgr) values($1)'
value_type = ['text']
qry = plpy.prepare(insert_qry,value_type)
rv = plpy.execute(qry, [mgr_str])
return 1
$$ LANGUAGE plpython3u;
An update :
Plpython accepts the query when it is written as follows with the user defined type specified with the variable in this format $1:: and stops throwing composite type not supported exceptions,
insert_qry = 'Insert into manager (mgr) values($1::person)'
value_type = ['text']
At the end, I really didn't have to do any extra casting operation on the database. It worked just by tweaking the variable as above.