Postgres: ERROR: value too long for type character(4) - postgresql

I'm new to Postgres and currently trying to write a function that takes in an integer and then calls another (definitely working) pre-written function with that input. If I call the pre-written function directly, e.g.:
select * from func(3456789);
I get the result I expect, with no errors. However, if I call it inside my function:
create or replace function my_func(_id integer)
returns setof Record
as $$
declare
rec Record;
begin
for rec in
select * from func(_id)
loop
return next rec;
end loop;
end;
$$ language plpgsql
;
where I call it with exactly the same parameter:
select * from my_func(3456789);
I get the following error:
ERROR: value too long for type character(4)
CONTEXT: PL/pgSQL function my_func(integer) line 5 at FOR over SELECT rows
Why are these two cases different, and how can I fix it?
EDIT:
func(_sid) returns this:
CREATE FUNCTION func(_sid integer) RETURNS SETOF Record
LANGUAGE plpgsql
AS $$ ...
and Record is defines like this:
create type Record as (code char(8), name char(4), num integer, work char(4));

Every line that is returned by your function func is mapped to a Record.
So the error you are getting says that one of the lines in the function result contains at column positions of name and/or work a value bigger than the one required by the columns (wich is 4).

Related

PostgreSQL: function with array argument

For the first time I'm trying to create function in PostgreSQL:
This function must accept parameter with array type. Array contains sequence of biginteger values. Size of array not arbitrary, but known in advance.
create function get_total (cols ARRAY) returns biginteger AS
$BODY$
begin
// Some logics
end;
$BODY$
Usage in query
select
stats.value1,
stats.value2,
get_total(array_agg(ARRAY[stats.value2, stats.value1]))
from stats;
It returns error:
type cols[] does not exist
SQL state: 42704
When I run in Select only array_agg(ARRAY[stats.value2, stats.value1]), I see, that array created successfully. So the problem in function parameter.
What am I doing wrong?
You have to declare the parameter as bigint[], which reads an array of type bigint e.g.
CREATE OR REPLACE FUNCTION get_total (bigint[])
RETURNS bigint AS
$$
BEGIN
-- your fancy logic goes here
END;
$$ LANGUAGE plpgsql
Function call:
SELECT get_total(ARRAY[1111111111111,1111111111111]);
An elegant alternative is to declare the parameter as VARIADIC. Doing so you may call your function with multiple parameters,e.g.:
CREATE OR REPLACE FUNCTION get_total (VARIADIC bigint[])
RETURNS bigint AS
$$
BEGIN
-- your fancy logic goes here
END;
$$ LANGUAGE plpgsql;
Function call:
SELECT get_total(1111111111111,1111111111111,1111111111111);
Demo: db<>fiddle
The syntax cols ARRAY is the same as cols[] and means “an array with elements of type cols”. That's why you get that error message for the function definition.
If the element type is bigint, the function should be defined as
CREATE FUNCTION get_total(cols bigint ARRAY) RETURNS bigint

postgresql function returns multiple columns

I am confused about the passing process of the parameter from functions created in Postgres:
create type IncorrectRecord as (pattern_number integer, uoc_number integer);
create or replace function text1(pattern text, uoc_threshold integer)
returns setof IncorrectRecord
as $$
begin
return next count(v1.code) as pattern_number, count(v2.code) as uoc_number
from (select * from q1_1 where code like pattern) as v1, (select
* from q1_1 where code like pattern and uoc > uoc_threshold) as v2;
return;
end
$$ language plpgsql;
I have modified some, there is no parameters errors but it still does not work.
when I tested it with
select *
from test1('ECO%', 8)
error: function returns two columns.
Is there any thing wrong with the type? How can I fix it?.
As the message says you are returning two columns. Return a composite type instead:
return next (
count(v1.code) as pattern_number, count(v2.code) as uoc_number
)::IncorrectRecord

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

Use of custom return types in a FOR loop in plpgsql

The following code that I use returns an integer 1:
CREATE TYPE my_test AS (
foo Integer
);
CREATE FUNCTION foo_out()
RETURNS SETOF Integer AS
$$
BEGIN
RETURN QUERY
SELECT 1 as foo;
END
$$
LANGUAGE plpgsql;
CREATE FUNCTION foo1()
RETURNS SETOF my_test
AS $$
DECLARE
x my_test;
BEGIN
FOR x IN
SELECT foo_out()
LOOP
RETURN NEXT x;
END LOOP;
END;
$$
LANGUAGE 'plpgsql';
select * from foo1();
But why does the same code return:
ERROR: invalid input syntax for integer: (1)
if I change the return type to:
CREATE FUNCTION foo_out()
RETURNS SETOF my_test
Which also should be an integer!? It could be the case that the system differs between the type integer and a custom type that includes an integer. What should be changed that the use of custom types is possible here?
my_test is a composite type, a row type, that contains a single integer field. It's not an integer.
When assigning to a record or row type in a FOR loop all output columns from the query form the row. Your SELECT needs to return a single, unnested integer column, which is then nested into a row type matching your custom type my_test.
You can also assign to a list of scalar variables in a FOR loop, in which case columns from the query are assigned left to right to variables as is - not forming a row.
If the column itself is a row type, you have one level of nesting to many. The text representation of a row containing an integer field is '(1)' (with parentheses!), and that's what you see in the error message.
You can fix that by extracting the integer field from the row with attribute notation:
SELECT (foo_out()).*
Or (more efficiently for multiple columns) by decomposing with:
SELECT * FROM foo_out()
Example Code
CREATE FUNCTION foo_out()
RETURNS SETOF my_test
LANGUAGE sql AS
'SELECT ''(1)''::my_test';
CREATE FUNCTION foo1()
RETURNS SETOF my_test
LANGUAGE plpgsql AS
$func$
DECLARE
x my_test;
BEGIN
FOR x IN
SELECT * FROM foo_out()
LOOP
RETURN NEXT x;
END LOOP;
END
$func$;
db<>fiddle here
Old sqlfiddle
Don't quote the language name plpgsql. It's an identifier.
Remember that looping is rarely needed, since most problems are more efficiently solved with a set-based approach (SQL only).
Related answers by Craig and Pavel:
Passing array of a composite type to stored procedure

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.