0

We have a table which consist of anonymous code/token which needs to be executed from procedure.

Here is the sample data:

Table:

create table tbl_tokens (id int,tokens text);

Record:

insert into tbl_tokens values(1,'do $$ 
declare id_cnt int; 
begin
    select count(1) into id_cnt 
    from emp 
    where id = $1;

    if(id_cnt>0)
    then 
        p_out := ''true'';
    else
        p_out := ''false'';
    end if;
end;
$$');

Procedure:

CREATE OR REPLACE PROCEDURE public.prc_token(IN in_token public.tbl_tokens)
LANGUAGE plpgsql
AS 
$procedure$
DECLARE v_out varchar(10);
BEGIN
    execute(in_token.tokens) using 1,out v_out; --Executing anonymous code
    if(v_out = 'true') then
    raise info '1';
    end if;
END;
$procedure$;

Procedure Call:

call public.prc_token(tbl_tokens);

Error:

ERROR:  column "tbl_tokens" does not exist
LINE 2:  call  public.prc_token(tbl_tokens);
3
  • A table can't be passed as an argument to a procedure. The procedure declaration says that the procedure expects an argument, in_token, of type row of table tbl_tokens. Anonymous blocks can't return values, so using v_out to get a result from EXECUTE(in_token.tokens) will not work. Commented Sep 6, 2024 at 13:56
  • @JohnH, What can be done in this scenario? Actually I'm migrating from oracle to postgresql, there are around hundreds of anonymous blocks stored in the actual table. Commented Sep 6, 2024 at 14:26
  • You cannot pass a parameter into a string constant. Commented Sep 6, 2024 at 16:28

1 Answer 1

1
  1. The do block tries to modify a p_out that hasn't been defined in it or in the procedure you want to run that block.

  2. If p_out is a typo and you wanted to modify the v_out you declared in the procedure, that won't be possible: the do block doesn't have access to it.

  3. You can't return things from a do block the way procedures can via out/inout parameters.

  4. PL/pgSQL execute doesn't have an out clause. It does offer an into clause to write its result to a variable.

  5. PostgreSQL has a boolean type. You don't need to use a varchar that says 'true' like in Oracle before 23c.

  6. You can declare a procedure that accepts records of a specific table but that's pretty impractical seeing that you can't combine the call with a select that would get you the row. You'd need to use more dynamic sql wrappers to fetch the row outside and inject it as a literal matching the row type, or bind/type out the literals as the parameter yourself.

  7. This:

    select count(1) into id_cnt 
    from emp 
    where id = $1;
    
    if(id_cnt>0)
    

    Sounds like you just want to check if any such row exists:

    if exists(select from emp where id = $1)
    

    That's shorter and faster. It does minimum work required to establish that, without having to count exactly how many rows meet the criteria.

  8. Make the procedure accept an int that corresponds to the tbl_tokens.id, then select the tokens from inside the procedure based on that.

  9. If you want the code in tokens to return something, you'll need to communicate via side-effects (make it write to a pre-defined temp table, then read those results from there after the call). Alternatively, you can replace the do blocks with a create statement of a temp procedure/function, followed by a call/select that invokes it.

demo at db<>fiddle

create table emp(id)as values(1::int),(2),(3);

create table tbl_tokens (id int,tokens text);

insert into tbl_tokens values(1,$tokens$
  drop function if exists pg_temp.f(public.emp.id%type);
  create function pg_temp.f(arg public.emp.id%type)
    returns boolean return exists(select from emp where id = arg); 
  select pg_temp.f($1);
  $tokens$);

create function public.prc_token(in_token_id public.tbl_tokens.id%type) 
  returns boolean as $procedure$
declare v_out boolean;
begin
  execute(select tokens from tbl_tokens where id=in_token_id)into v_out using 1;
  return v_out;
end $procedure$ language plpgsql;

select public.prc_token(1);
prc_token
t
Sign up to request clarification or add additional context in comments.

1 Comment

The concept can/does work. But from security, maintainability, observability and performance point of view, it looks like a nightmare.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.