O exemplo dado pode ser totalmente substituído por
RETURN QUERY :BEGIN
RETURN QUERY SELECT y_.y, 'hi' FROM generate_series(1,10,1) AS y_(y)
END;
que será muito muito mais rápido.
Em geral, você deve evitar a iteração sempre que possível e, em vez disso, favorecer as operações orientadas a conjuntos.
Onde
return next em um loop é inevitável (o que é muito raro e principalmente limitado a quando você precisa de tratamento de exceção) você deve definir OUT valores de parâmetro ou parâmetros de tabela e, em seguida, return next sem argumentos. Neste caso, seu problema é a linha
SELECT yr.y, 'hi'; que não faz nada. Você está assumindo que o destino implícito de um SELECT são os parâmetros de saída, mas esse não é o caso. Você teria que usar os parâmetros out como variáveis de loop como @peterm fez, usar atribuições ou usar SELECT INTO :FOR yr IN SELECT * FROM generate_series(1,10,1) AS y_(y)
LOOP
RAISE NOTICE 'Computing %', yr.y;
y := yr.y;
result := 'hi';
RETURN NEXT;
END LOOP;
RETURN;