PSQLException: ERROR: syntax error at or near "test" - postgresql

I'm getting the same error as in the title:
CREATE OR REPLACE FUNCTION func(param varchar) RETURNS varchar AS
'BEGIN
LOCK public.routes;
return (SELECT * FROM public.routes WHERE guid = 'test');
END;' LANGUAGE plpgsql
What might be the problem? I can execute the same in console and it's gonna work.

You need to escape single quotes embedded in string literals by doubling them:
CREATE OR REPLACE FUNCTION func(param varchar) RETURNS varchar AS
'BEGIN
LOCK public.routes;
return (SELECT * FROM public.routes WHERE guid = ''test'');
END;' LANGUAGE plpgsql
That's the reason why people usually use dollar quoting for the body of functions:
CREATE OR REPLACE FUNCTION func(param varchar) RETURNS varchar AS
$body$
BEGIN
LOCK public.routes;
return (SELECT * FROM public.routes WHERE guid = 'test');
END;
$body$
LANGUAGE plpgsql
However, even if you get the syntax right: the function will not work. It is defined to return a single (scalar) value of type varchar but it returns the all rows from the table routes. If you want to return multiple rows, you need to define the function as returns setof or returns table. In your case returns setof routes would be applicable:
CREATE OR REPLACE FUNCTION func(param varchar)
RETURNS setof public.routes
AS
$body$
BEGIN
LOCK public.routes;
return (SELECT * FROM public.routes WHERE guid = 'test');
END;
$body$
LANGUAGE plpgsql
If you intend to return the value of a single column of a single row (assuming that guid is defined as PK or unique), then indeed returns varchar would work. But then you should change the select statement to select some_column from .. or something similar

Related

Return data from Common Table Expression in postgres

I am trying to return some data I have from Common Table Expression to my backend but unable to because Postgres doesn't see the table.
CREATE OR REPLACE FUNCTION request(
question_id_func INTEGER,
requester_account_id_func INTEGER,
counter_func NUMERIC
) RETURNS INTEGER AS $$
with notif AS (
INSET INTO notification(...) VALUES (...) RETURNING *
)
UPDATE question....
RETURN (SELECT notif_id FROM notif);
END $$ LANGUAGE PLPGSQL
Does anyone has a better idea how you can extract the data from CTE and return it?
Much appreciated.
You will need to put your UPDATE statement into a CTE, and then assign the output to a function variable using a final SELECT statement.
For example:
CREATE OR REPLACE FUNCTION request(
question_id_func INTEGER,
requester_account_id_func INTEGER,
counter_func NUMERIC
) RETURNS INTEGER AS $body$
DECLARE
result integer;
BEGIN
WITH notif AS (
INSERT INTO notification(...) VALUES (...) RETURNING *
),
question_update AS (
UPDATE question....
)
SELECT notif.notif_id INTO result FROM notif;
RETURN result;
END $body$ LANGUAGE PLPGSQL

How to use RETURN SETOF RECORD with dynamic column?

I have some problem to get value of query. I need to get return with dynamic column according to query. For this case i can't use RETURN TABLE statement because we must define the column. Please Help :). Thank you
CREATE OR REPLACE FUNCTION public.FN_test(P_Company varchar, P_fiscal_periode varchar, P_opt int)
RETURNS SETOF RECORD
AS $BODY$
DECLARE
Details RECORD;
BEGIN
create table Details as
select * from M_Account;
RETURN QUERY select * from Details;
drop table Details;
END;
$BODY$
LANGUAGE plpgsql
this is result error
select FN_test('1000', '201808', 4)
> ERROR: set-valued function called in context that cannot accept a set
CONTEXT: PL/pgSQL function fn_test(character varying,character varying,integer) line 9 at RETURN QUERY
If you return a record type, you must define the columns in the list to return from these functions(when you call it) and call the function with this format:
select * from FN_test('1000', '201808', 4)
as (f1 data type, f2 data type) --list of columns
Could also return a JSON type (as generic resuldt) and then process it:
CREATE OR REPLACE FUNCTION public.FN_test3(P_Company varchar, P_fiscal_periode varchar, P_opt int)
RETURNS setof json
AS $BODY$
DECLARE
Details RECORD;
BEGIN
create table Details as
select row_to_json(M_Account.*) from M_Account; --JSON function
RETURN QUERY select * from Details;
drop table Details;
END;
$BODY$
LANGUAGE plpgsql
and the call it:
select * from FN_test('1000', '201808', 4)

How to get entire table data or multiple rows returned from a function in PG/PLSQL with pgAdmin 4.2.?

I tried using setof and table. While creating function in pgAdmin 4.2 there is no return type called setof or table. If I create function with setof and table name as a selected return type, it only returns one row of table.
CREATE FUNCTION pgsql_returnrecords() RETURNS SETOF RECORD(name char, city, char, id integer) AS
$BODY$
DECLARE
rec RECORD;
BEGIN
select name,city,id INTO rec from test;
return next rec;
END;
$BODY$ language plpgsql;
I want my function to return table data with all rows and columns.
It's either returns setof record or returns table(....) or setof table_name With returns setof record you have to specify the column names when using the function.
You are also not returning a complete result, because you only fetch a single row, put it into the record and return that. To return a real "set" you need to use return query in PL/pgSQL. But such a function is much better written as a SQL function:
CREATE FUNCTION pgsql_returnrecords()
RETURNS table(name text, city text, id integer)
AS
$BODY$
select name,city,id
from test;
$BODY$
language sql;
If you want to always return a complete row from the table test you can simplify that using returns setof test instead of returns table(..)
CREATE FUNCTION pgsql_returnrecords()
RETURNS setof test
AS
$BODY$
select *
from test;
$BODY$ language sql;
Or, if you insist on PL/pgSQL:
CREATE FUNCTION pgsql_returnrecords()
RETURNS table(name text, city text, id integer)
AS
$BODY$
BEGIN
return query
select name,city,id
from test;
END;
$BODY$
language plpgsql;
In both cases you have to use the function like a table in the FROM clause:
select *
from pgsql_returnrecords() ;

Rename the column name of a stored function

I've got a postgresql stored procedure, which is returning an integer.
When I call that function, the result is returned with the function name as column name.
For example the name of the function is: "add-person". The column name, when invoking the function, is "add-person".
Is there a way to make the database return the integer with a self-choosen column name? For example "id"?
I think it is pretty easy, but I currently miss the forests for the trees..
Edit:
What i'd missed to tell, is that the return value is a variable, like so:
CREATE OR REPLACE FUNCTION "scheme"."add-person"(arggivenname character varying, argfamilyname character varying) RETURNS integer AS
$BODY$
DECLARE
varResponse integer;
BEGIN
-- Operations before
INSERT INTO "scheme"."table"
(
given_name,
family_name
)
VALUES
(
arggivenname,
argfamilyname
)
RETURNING
"id"
INTO
varResponse;
-- Operations after
RETURN varResponse;
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
You can us the AS statement for that. That means:
Select add-person() AS yourcolumnname
To have a named column from a function it is necessary to create a type and return that type from the function
create type mytype as (mycolumn integer);
create or replace function ri()
returns mytype as $$
select 1;
$$ language sql;
select * from ri();
mycolumn
----------
1
Edit
Or much simpler without the type creation as in #pozs comment:
create or replace function ri(out mycolumn integer)
as $$
select 1;
$$ language sql;

PL/Proxy returning Unsupported Type on Stored Procedure Call

I've setup a Stored Procedure in PL/Proxy to make a query, and receive some RECORDs back.
In PL/Proxy:
CREATE OR REPLACE FUNCTION query_autocomplete(q text, i_id bigint)
RETURNS SETOF RECORD AS $$
CLUSTER 'autocompletecluster';
RUN ON i_id;
$$ LANGUAGE plproxy;
In each Partition:
CREATE OR REPLACE FUNCTION query_autocomplete(q text, i_id bigint)
RETURNS SETOF RECORD AS $$
DECLARE
rec RECORD;
BEGIN
FOR rec IN EXECUTE q
LOOP
RETURN NEXT rec;
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
As you've likely guessed, this is hitting a defined SERVER in PGSQL called 'autocompletecluster'. The query string that I'm sending through is as follows:
$sql = "SELECT * FROM autocomplete WHERE member_id = :memberId";
$query = $this->db->prepare("SELECT query_autocomplete('{$sql}',1234");
It's returning the following:
SQLSTATE[XX000]: Internal error: 7 ERROR: PL/Proxy function public.query_autocomplete(0): unsupported type
The table that query is hitting is defined as such:
CREATE TABLE autocomplete (
id character varying(100) NOT NULL,
extra_data hstore,
username character varying(254),
member_id bigint
);
What am I doing wrong?
The error strongly suggests that PL/Proxy doesn't support SETOF RECORD. Try instead defining your functions to return autocomplete%rowtype or, failing that, RETURNS TABLE (...) with a matching columns-set.