Calling a stored procedure within a stored procedure

半世苍凉 提交于 2019-11-28 05:40:05

问题


I am trying to call a function within a function using sql on postgres 9.3.

This question is related to another post by me.

I have written the below function. So far I have failed to incorporate any kind of save-output (COPY) statement, so I am trying to work around this by creating a nested function print-out function.

CREATE FUNCTION retrieve_info(TEXT, TEXT) RETURNS SETOF   
retrieve_info_tbl AS $$
 SELECT tblA.id, tblA.method, tblA.species, tblA.location
 FROM tblA
 WHERE method=$1 AND species=$2
 GROUP BY id, method, species
 ORDER BY location
$$ LANGUAGE 'sql';

The above function works.

An attempt to create a nested function.

CREATE FUNCTION print_out(TEXT, TEXT) RETURNS void AS $$
 COPY (SELECT * FROM retrieve_info($1, $2)) TO 'myfilepath/test.csv'    
 WITH CSV HEADER;
$$ LANGUAGE 'sql';

Calling nested function.

SELECT * FROM print_out('mtd1','sp1');

OUTPUT

The above gives this ERROR: column "$1" does not exist SQL state: 42P02 Context: SQL function "print_out" statement 1. However, when substituting the arg1, arg2 in print_out() with 'mtd1','sp1' the correct output is printed to test.csv (as seen below)

id | method | ind | location
----------------------------
1a | mtd1   | sp3 | locA
1d | mtd1   | sp3 | locB

How would I get the arg1, arg2 of retrieve_info() to call arg1, arg2 properly within print_out()?

I am completely stuck. Would appreciate any pointers, thanks


回答1:


COPY is a bit odd as it sort of treats its query argument as a string even though it isn't written as a string. The result is that the query:

SELECT * FROM retrieve_info($1, $2)

isn't executed in the context of the function, it is executed in the context of COPY itself. Even though you say:

copy (select * from t) ...

it is treated more as though you wrote:

copy 'select * from t' ...

so by the time the query is executed, the function parameters no longer have any meaning, the query argument to COPY may look like it would behave like a closure in other languages but it doesn't, it acts more like a string that gets passed to eval.

You can get around this strangeness by using the usual Kludge of Last Resort: dynamic SQL. You should get better results if you write your function to use string wrangling and EXECUTE:

create or replace function print_out(text, text) returns void as $$
begin
    execute 'copy ('
         || 'select * from retrieve_info'
         ||     '(' || quote_literal($1) || ',' || quote_literal($2) || ')'
         || ') to ''myfilepath/test.csv'' with csv header;';
end;
$$ language plpgsql;



回答2:


Are x and y quoted intentionally?

COPY (SELECT * FROM retrieve_info('x','y')) TO 'myfilepath/test.csv'

You are not sending the x and y arguments of print_out to retrieve_info - rather, you are sending the strings 'x' and 'y'. Assuming you don't have records with method='x' AND species='y', it's of little wonder you get no results.

Try this instead:

COPY (SELECT * FROM retrieve_info(x,y)) TO 'myfilepath/test.csv'


来源:https://stackoverflow.com/questions/19918385/calling-a-stored-procedure-within-a-stored-procedure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!