Postgresql - Returned type record does not match expected type uuid - postgresql

I have very simple function that should return few rows including the uuid type as the first column.
Function:
CREATE OR REPLACE FUNCTION public.export_wizard()
RETURNS TABLE(id uuid, my_column text)
LANGUAGE plpgsql
AS $function$
BEGIN
return query select (w.id, w.my_column) from wizard w;
END;
$function$
;
Table (short version):
CREATE TABLE IF NOT EXISTS public.wizard
(
id uuid NOT NULL,
my_column text COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT wizard_pkey PRIMARY KEY (id)
)
After calling the function like this: select * from export_wizard();
I got an error:
SQL Error [42804]: ERROR: structure of query does not match function result type
Detail: Returned type record does not match expected type uuid in column 1.
Where: PL/pgSQL function export_wizard() line 3 at RETURN QUERY
Thanks for any advices.

I made terrible mistake by adding (no idea why) brackets in SELECT statement as mentioned by #Adrian Klaver.
Correct: return query select w.id, w.my_column from wizard w;

Related

Ambiguous column reference - it could refer to either a PL/pgSQL variable or a table column?

I am getting the following error in PostgreSQL:
[42702] ERROR: column reference "topicid" is ambiguous Detail: It
could refer to either a PL/pgSQL variable or a table column. Where:
PL/pgSQL function topics(integer) line 3 at RETURN QUERY
I understand that to mean there is a parameter and a table column with the same name. Except that I cannot see where it is because the only parameter I have is _typeid and not topicid.
Where is the problem exactly in this function:
CREATE FUNCTION topics(_typeid integer DEFAULT NULL::integer)
RETURNS TABLE(topicid integer, typeid integer, topic character varying)
LANGUAGE plpgsql
AS
$$
BEGIN
RETURN QUERY SELECT
topicid
,typeid
,topic
FROM
topic
WHERE
_typeid IS NULL
OR
typeID = _typeid
ORDER BY
topic ASC;
END
$$;
If I refactor it to just use sql then it works fine like such:
CREATE FUNCTION topics(_typeid integer DEFAULT NULL::integer)
RETURNS TABLE(topicid integer, typeid integer, topic character varying)
LANGUAGE sql
AS
$$
SELECT
topicid
,typeid
,topic
FROM
topic
WHERE
_typeid IS NULL
OR
typeID = _typeid
ORDER BY
topic ASC;
$$;
The conflict is between the variables in RETURNS TABLE and the field names returned from the query. Table qualify the field names in the query e.g. topic.topicid, topic.typid, topic.topic.

Postgres function input parameter as TEXT Array problem

My Table looks like
CREATE TABLE dev.clbk_logs
(
id bigint NOT NULL,
clbk_typ character varying(255) COLLATE pg_catalog."default",
clbk_json json,
cre_dte timestamp without time zone,
ld_id bigint,
ld_num character varying(255) COLLATE pg_catalog."default",
mod_dte timestamp without time zone,
CONSTRAINT clbk_logs_pkey PRIMARY KEY (id)
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
My function is
CREATE OR REPLACE FUNCTION dev.my_method(p_callback_types TEXT[], p_days_ago INT)
RETURNS SETOF dev.clbk_logs
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
return query
SELECT * FROM dev.clbk_logs
WHERE (clbk_Typ::TEXT) IN (($1)) AND (current_date - cre_dte::date)< p_days_ago;
END;
$BODY
Can someone please help what is wrong in above, and should make expected result.
I wanted to pass an array of string and in query.
Error I am getting is
LINE 2: WHERE (clbk_Typ::TEXT) IN (($1)) AND (current_date - cre_...
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT * FROM dev.clbk_logs
WHERE (clbk_Typ::TEXT) IN (($1)) AND (current_date - cre_dte::date)< p_days_ago
CONTEXT: PL/pgSQL function dev.my_method(text[],integer) line 3 at RETURN QUERY
SQL state: 42883
You need to use = any() not IN with an array.
The cast to ::text is also not needed. And for readability I would recommend using the parameter name, rather than the number:
CREATE OR REPLACE FUNCTION dev.my_method(p_callback_types TEXT[], p_days_ago INT)
RETURNS SETOF dev.fourkites_clbk_logs
LANGUAGE plpgsql
AS $BODY$
BEGIN
return query
SELECT *
FROM dev.fourkites_clbk_logs
WHERE clbk_Typ = any (p_callback_type)
AND (current_date - cre_dte::date) < p_days_ago;
END;
$BODY
Note that your condition on cre_dte can't use an index if you ever create one. If you want that condition to be able to use an index, change it to:
and cre_dte >= current_date - p_days_ago;

Constructing array literal as input for PL/pgSQL function

How should an array with elements of a composite type be included in a function call?
After consulting the resources online and attempting the different variants, I continue to get parser errors. Below I've included the types, tables, functions, and execution attempts.
Type
CREATE TYPE jobs_v0.insertable_program AS (
handle text,
zip bytea
);
Tables
CREATE TABLE jobs_v0.jobs (
id bigserial PRIMARY KEY NOT NULL,
manifest_cid text NOT NULL,
created_at timestamp NOT NULL DEFAULT now()
);
CREATE TABLE jobs_v0.programs (
id bigserial PRIMARY KEY NOT NULL,
job bigserial REFERENCES jobs_v0.jobs(id) NOT NULL,
handle text NOT NULL,
package bytea NOT NULL
);
Function:
CREATE OR REPLACE FUNCTION jobs_v0.insert_job(
manifest_cid text,
programs jobs_v0.insertable_program[]
) RETURNS void AS
$$
DECLARE
job_id jobs_v0.jobs.id%TYPE;
program jobs_v0.insertable_program;
inserted_programs jobs_v0.programs[];
BEGIN
-- Insert job
INSERT INTO jobs_v0.jobs(manifest_cid) VALUES (manifest_cid)
RETURNING id INTO job_id;
-- Insert programs
INSERT INTO jobs_v0.programs(job, handle, package)
SELECT job_id, * FROM unnest(programs)
RETURNING * INTO inserted_programs;
END;
$$ LANGUAGE plpgsql;
Execution attempts and errors:
select jobs_v0.insert_job('QmTXzATwNfgGVukV1fX2T6xw9f6LAYRVWpsdXyRWzUR2H9', '{"(main, 0xdeadbeef)"}'::jobs_v0.insertable_program[]);
ERROR: malformed array literal: "12"
DETAIL: Array value must start with "{" or dimension information.
CONTEXT: PL/pgSQL function jobs_v0.insert_job(text,jobs_v0.insertable_program[]) line 12 at SQL statement
---
select jobs_v0.insert_job('QmTXzATwNfgGVukV1fX2T6xw9f6LAYRVWpsdXyRWzUR2H9', array[row('main', E'\\xdeadbeef')]::jobs_v0.insertable_program[]);
ERROR: malformed array literal: "13"
DETAIL: Array value must start with "{" or dimension information.
The array literal should look like this:
select jobs_v0.insert_job(
'QmTXzATwNfgGVukV1fX2T6xw9f6LAYRVWpsdXyRWzUR2H9',
'{"(main,\"\\\\xdeadbeef\")"}'
);
But the bug is in the function code:
INSERT INTO jobs_v0.programs(job, handle, package)
SELECT job_id, * FROM unnest(programs)
RETURNING * INTO inserted_programs;
The * in RETRUNING * does refer to all columns of jobs_v0.programs, not to all columns of jobs_v0.insertable_program, as you seem to expect.
Besides, inserted_programs cannot be of an array type, it would have to be of type jobs_v0.insertable_program and can contain only a single result. If the INSERT inserts several rows, only the first one will be returned.

Using parameter as column name in Postgres function

I have a Postgres table bearing the following form
CREATE TABLE "public"."days"
(
"id" integer NOT NULL,
"day" character varying(9) NOT NULL,
"visits" bigint[] NOT NULL,
"passes" bigint[] NOT NULL
);
I would like to write a function that allows me to return the visits or the passees column as its result for a specified id. My first attempt goes as follows
CREATE OR REPLACE FUNCTION day_entries(INT,TEXT) RETURNS BIGINT[] LANGUAGE sql AS
'SELECT $2 FROM days WHERE id = $1;'
which fails with an error along the lines of
return type mismatch in function declared to return bigint[]
DETAIL: Actual return type is text.
If I put in visits in place of the $2 things work just as expected. It would make little sense to define several functions to match different columns from the days table. Is there a way to pass the actual column name as a parameter while still keeping Postgres happy?
You can't use parameters as identifiers (=column name), you need dynamic SQL for that. And that requires PL/pgSQL:
CREATE OR REPLACE FUNCTION day_entries(p_id int, p_column text)
RETURNS BIGINT[]
AS
$$
declare
l_result bigint[];
begin
execute format('SELECT %I FROM days WHERE id = $1', p_column)
using p_id
into l_result;
return l_result;
end;
$$
LANGUAGE plpgsql;
format() properly deals with identifiers when building dynamic SQL. The $1 is a parameter placeholder and the value for that is passed with the using p_id clause of the execute statement.

Function returns only one column when return type is record type postgres

I have a function that has the return type of record.
Below is the function am using, basically what the function does is , it takes in input paramter and queries the database to return the columns:
drop function if exists test_proc(sr_number1 bigint);
create or replace function test_proc(sr_number1 bigint) RETURNS record /*SETOF tbl*/ AS $$
declare
i integer default 0;
record_type record;
begin
select sr_num,product_number,phone,addr into record_type from my_table where sr_num=sr_number1;
return record_type;
end
$$ LANGUAGE plpgsql;
Unfortunately, when I execute the function as
select test_proc(12345); I get the result as a comma separated list in just one column like (sr_num,product_number,phone,addr). But what I was hoping to have it return was a table row with the column values and their respective column names.
I also tried executing the function as
select * from test_proc(12345); but get the following error
ERROR: a column definition list is required for functions returning "record"
When querying a function that returns a record you must specify the type of record you want to get in the result
select * from test_proc(12345) f(b bigint, t text);
This should work.
A better solution is to declare the type of record in the function
CREATE OR REPLACE FUNCTION test_proc(sr_number1 bigint)
RETURNS TABLE(b bigint, t text) AS $$ $$