Relation doesn't exists while calling postgres function with parameters - postgresql

I have a function
CREATE OR REPLACE FUNCTION test_function(
g geometry, _tbl regclass, _tile regclass)
RETURNS SETOF geometry AS
$BODY$
BEGIN
return query EXECUTE format('select geom from %s where tile_id = %s::varchar', _tbl, _tile);
RETURN;
END
$BODY$
LANGUAGE plpgsql
which works if call the function like this
select test_function(st_geometryfromtext('POLYGON((-119.896896986135 39.2639920102033,-119.896896986135 39.2641790174996,-119.896710996922 39.2643649879886,-119.896710996922 39.2645519952849,-119.896896986135 39.2639920102033))'),
'public.test', '123')
but gives error when I call function with different _tile parameter
select test_function(st_geometryfromtext('POLYGON((-119.896896986135 39.2639920102033,-119.896896986135 39.2641790174996,-119.896710996922 39.2643649879886,-119.896710996922 39.2645519952849,-119.896896986135 39.2639920102033))'),
'public.ec_1_eur_1', '123_123_123')
gives error ERROR: relation "123_123_123" does not exist
why does it not throw error for '123' but '123_123_123'. How should I solve this?
When adding varchar for _tile instead of regclass, it doesn't handle quotes within quotes
CREATE OR REPLACE FUNCTION public.test_function(
g geometry,
_tbl regclass,
tile varchar)
RETURNS SETOF geometry AS
$BODY$
BEGIN
return query EXECUTE format('select geom from %s where tile_id = %s::varchar', _tbl, tile);
RETURN;
END
$BODY$
LANGUAGE plpgsql
I get an issue
ERROR: syntax error at or near "_123_123"
LINE 1: select geom from test where tile_id = 123_123_123::var...

You have to use %I and %L to quote correctly and avoid SQL injection:
CREATE OR REPLACE FUNCTION public.test_function(
g geometry,
_tbl regclass,
tile varchar)
RETURNS SETOF geometry AS
$BODY$
BEGIN
return query EXECUTE format('select geom from %I where tile_id = %L::varchar', _tbl, tile);
RETURN;
END
$BODY$
LANGUAGE plpgsql

Related

Argument not taking the value from Postgres function

I have a simple Postgres function where I want to take table_name as a parameter and pass it into an argument and delete the data from table by condition.
CREATE OR REPLACE FUNCTION cdc.audit_refresh(tablename text)
RETURNS integer AS
$$
BEGIN
delete from tablename where id<4;
RETURN(select 1);
END;
$$ LANGUAGE plpgsql;
select cdc.audit_refresh('cdc.adf_test');
But it throws out an error that tablename
ERROR: relation "tablename" does not exist in the delete statement.(refer snapshot)
What you want to achieve is to execute Dynamic SQL statements. You can do this with EXECUTE. See more here
CREATE OR REPLACE FUNCTION audit_refresh(tablename text)
RETURNS integer AS
$$
DECLARE
stmt TEXT;
BEGIN
stmt = 'delete from '||tablename||' where id<4;';
EXECUTE stmt;
RETURN 1;
END
$$ LANGUAGE plpgsql;

Select Statement using Stored Procedure

May I ask on how to call a method when the content of the stored procedure is about select statement? (Using postgreSQL)
CREATE OR REPLACE PROCEDURE select_table(table_name VARCHAR(255))
language plpgsql
as $$
BEGIN
EXECUTE('SELECT * FROM' || ' ' || quote_ident(table_name));
END $$;
CALL select_table('employee_table');
EDITED(USING FUNCTION)
CREATE OR REPLACE FUNCTION select_table(table_name VARCHAR(255))
language plpgsql
as $$
BEGIN
SELECT * FROM table_name
RETURN table_name;
END $$;
In PostgreSQL procedures doesn't execute any select statements and doesn't have return.
For returning data you can use functions. But functions also cannot return different structural data, examples:
CREATE OR REPLACE FUNCTION fr_test()
RETURNS TABLE(id integer, bookname character varying)
LANGUAGE plpgsql
AS $function$
begin
return QUERY
SELECT tb.id, tb.bookname from rbac.books tb;
end;
$function$
;
or
CREATE OR REPLACE FUNCTION fr_test()
RETURNS setof public.books
LANGUAGE plpgsql
AS $function$
begin
return QUERY
SELECT * from public.books;
end;
$function$
;
But for returning difference tables you can do it using procedures and using out refcursor, like as in Oracle. For example:
create or replace procedure pr_test(OUT r1 refcursor)
as $$
begin
open r1 for
select * from public.books;
end;
$$ language plpgsql;

Execute decode function stored in bytea column

I have a bytea column in a table that contains a function decode(). What I have done to get the actual data is as follows:
select filename, convert_from(data,'UTF-8') from attachments limit 20; //this returns me decode function
select decode(E'...','hex'); // I am executing the above returned function
The above is fine as long as I have to select one row. But now my requirement is to get more than one result. How can I get the result in single query? I have tried using pl/pgsql
CREATE OR REPLACE FUNCTION get_data(integer, _type anyelement, OUT _result anyelement)
AS
$x$
BEGIN
EXECUTE
'SELECT ' || (select convert_from(data,'UTF-8') as data from attachments limit $1)
INTO _result;
END;
$x$
LANGUAGE plpgsql;
But this works only for single row and single column. What I want is a single query to fetch 2 columns without using pl/pgsql if possible. I am using this query from my Java based web app.
Thanks!
You need procedural code for this, since there is no provision for dynamic statements in SQL.
The following function converts all attachments:
CREATE FUNCTION getemall(
IN v_type anyelement,
OUT v_result anyelement
) RETURNS SETOF anyelement
LANGUAGE plpgsql AS
$$DECLARE
v_stmt text;
BEGIN
FOR v_stmt IN
SELECT convert_from(data,'UTF-8')
FROM attachments
LOOP
EXECUTE v_stmt INTO v_result;
RETURN NEXT;
END LOOP;
END;$$;
This is how I have written the function with few changes
CREATE OR REPLACE FUNCTION getmeall(tName text, fNameCol text, dataCol text,fSize
numeric)
RETURNS TABLE(bdata bytea, fname text) LANGUAGE plpgsql AS
$$DECLARE
v_stmt text;
v_name text;
BEGIN
FOR v_stmt,v_name IN
EXECUTE format('SELECT encode(%s, ''escape''), %s FROM %s
WHERE $1 IS NOT NULL AND $2 IS NOT NULL LIMIT $3'
, dataCol, fNameCol, tName)
USING dataCol, fNameCol, fSize
LOOP
fname:=v_name;
IF strpos(v_stmt,'decode') = 1 THEN
EXECUTE 'SELECT ' || v_stmt INTO bdata;
ELSE
bdata:=v_stmt;
END IF;
RETURN NEXT;
END LOOP;
END;$$;
And finally calling it this way.
select * from getmeall('attachments', '"filename"', '"data"',2)

Postgresql stored procedure return table all columns

A function is created. The function has a input parameter. I can return a column but I want to return all table columns. Also I want to do if result is zero the function return just 0. How can I do it?
Here the error result.
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 dwgcould.returnallcolumns(character varying) line 3 at SQL statement
********** Error **********
ERROR: query has no destination for result data
SQL state: 42601
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Context: PL/pgSQL function dwgcould.returnallcolumns(character varying) line 3 at SQL statement
CREATE OR REPLACE FUNCTION dwgcould.returnallcolumns(IN sessionId character varying)
RETURNS SETOF public.mytable AS
$BODY$
BEGIN
SELECT * FROM public.mytable WHERE session_id=returnallcolumns.sessionId ORDER BY pro_id DESC LIMIT 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
If you want to return a result, you need to use return query in PL/pgSQL as documented in the manual
CREATE OR REPLACE FUNCTION dwgcould.returnallcolumns(IN sessionId character varying)
RETURNS SETOF public.mytable AS
$BODY$
BEGIN
return query --<< this was missing
SELECT *
FROM public.mytable
WHERE session_id = returnallcolumns.sessionId
ORDER BY pro_id DESC LIMIT 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
But you don't need PL/pgSQL for this, a simple SQL function will be more efficient:
CREATE OR REPLACE FUNCTION dwgcould.returnallcolumns(IN sessionId character varying)
RETURNS SETOF public.mytable AS
$BODY$
SELECT *
FROM public.mytable
WHERE session_id = returnallcolumns.sessionId
ORDER BY pro_id DESC LIMIT 1;
$BODY$
LANGUAGE sql;
How to get all data from dynamic table in the PostgreSQL database which name pass as in parameter?
DROP FUNCTION IF EXISTS schemaName."GetAllDataFromDynamicTable";
CREATE OR REPLACE FUNCTION schemaName."GetAllDataFromDynamicTable"(IN P_DynamicTableName text)
RETURNS SETOF schemaName."P_DynamicTableName"
AS $$
BEGIN
return query
SELECT *
FROM schemaName."P_DynamicTableName" -- this table name every time change
END;
$$
LANGUAGE plpgsql;

Table name as variable parameter

I made a function in pgadmin
create or replace function get_source2(a text)
returns integer as
$$
declare
a text;
geom geometry;
begin
select get_source(geom)
from a;
end;
$$
language plpgsql;
I want input a by table name How can I do? I try to like this
select get_source2('postgis.center')
but I get:
ERROR: relation "a" does not exist LINE 2: from a help me
try this:
create or replace function get_source2(a text)
returns integer as
$$
declare
geom geometry;
begin
execute 'select get_source(geom) from '||quote_ident(a) into geom;
return geom;
end;
$$
language plpgsql;