Home > Net >  how to cancel Pipe row?
how to cancel Pipe row?

Time:05-31

I have a pipeline function. If I catch an exception, I want to return no lines. Even if the exception occurs after the first utilisation of pipe row.

CREATE TYPE a_r IS OBJECT (a1 VARCHAR (1), a2 VARCHAR (1));

CREATE TYPE a_t IS TABLE OF a_r;

CREATE or replace FUNCTION get_a
    RETURN a_t
    PIPELINED
IS
BEGIN
    FOR c IN (SELECT '1' a , '2' b FROM DUAL)
    LOOP
        PIPE ROW (a_r(c.a,c.b));
    END LOOP;
    FOR a
            IN (SELECT 'a2' a,
                       'b' b
                  FROM DUAL)
        LOOP
            PIPE ROW (a_r(a.a,a.b));
        END LOOP;
exception
        WHEN VALUE_ERROR
        THEN
            DBMS_OUTPUT.put_line ('VALUE_ERROR');
        WHEN OTHERS
        THEN
            DBMS_OUTPUT.put_line ('other');
    
END;

select * from table(get_a())

In this example, Before the error ('ab' is not varchar2(1)) occurs, the first line is already piped. But I want nothing to be returned. Is there a way to write cancel what was piped in the exception block?

code

CodePudding user response:

No because the client may already have consumed the row.

You could code your function so that it fills a local collection with data and only at the end decides whether to iterate through the collection to actually return the rows. That will require more memory since you're materializing the entire result set before returning it and defeats some of the performance benefits of using pipelined table functions.

Something like this would appear to do what you want

CREATE or replace FUNCTION get_a
    RETURN a_t
    PIPELINED
IS
  l_a_t a_t := new a_t();
BEGIN
    FOR c IN (SELECT '1' a , '2' b FROM DUAL)
    LOOP
        l_a_t.extend;
        l_a_t( l_a_t.count ) := a_r(c.a,c.b);
    END LOOP;
    FOR a
            IN (SELECT 'a2' a,
                       'b' b
                  FROM DUAL)
        LOOP
            l_a_t.extend;
            l_a_t( l_a_t.count ) := a_r(a.a,a.b);
        END LOOP;
        
   for i in 1 .. l_a_t.count
   loop
     pipe row( l_a_t(i) );
   end loop;
exception
        WHEN VALUE_ERROR
        THEN
            DBMS_OUTPUT.put_line ('VALUE_ERROR');
        WHEN OTHERS
        THEN
            DBMS_OUTPUT.put_line ('other');
    
END;
/

See this dbfiddle

  • Related