Você obtém isso porque seu código atribui um escalar ao tipo de saída. Você precisa converter a variável para corresponder ao destino de atribuição. Então:
SELECT type_struct(counter)
INTO rec
FROM dual;
Você não precisa necessariamente de uma função em pipeline. Podemos usar
table()
com qualquer função que retorne uma coleção. Aqui está uma implementação muito mais simples, que requer apenas um UDT.
CREATE TYPE tp_numbers AS TABLE OF number;
/
CREATE OR REPLACE FUNCTION gen_nums (na NUMBER, nb NUMBER)
RETURN tp_numbers
IS
return_value tp_numbers ;
BEGIN
SELECT (na + level) - 1
bulk collect INTO return_value
FROM dual
connect by level <= nb;
RETURN return_value ;
END gen_nums;
/