Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Uma sintaxe para avaliação lenta/curto-circuito personalizado de parâmetros de função


A avaliação preguiçosa pode ser (parcialmente) implementada usando cursores de referência, compilação condicional ou execução imediata. O tipo ANYDATA pode ser usado para passar dados genéricos.

Cursor de referência


Os cursores de referência podem ser abertos com uma instrução SQL estática, passados ​​como argumentos e não serão executados até que sejam necessários.

Embora isso literalmente responda à sua pergunta sobre avaliação preguiçosa, não tenho certeza se é realmente prático. Este não é o uso pretendido de cursores de referência. E pode não ser conveniente adicionar SQL a tudo.

Primeiro, para provar que a função slow está em execução, crie uma função que simplesmente durma por alguns segundos:
grant execute on sys.dbms_lock to <your_user>;

create or replace function sleep(seconds number) return number is
begin
    dbms_lock.sleep(seconds);
    return 1;
end;
/

Crie uma função para determinar se a avaliação é necessária:
create or replace function do_i_have_to_trace return boolean is
begin
    return true;
end;
/

Esta função pode realizar o trabalho executando a instrução SQL. A instrução SQL deve retornar algo, mesmo que você não queira um valor de retorno.
create or replace procedure trace_something(p_cursor sys_refcursor) is
    v_dummy varchar2(1);
begin
    if do_i_have_to_trace then
        fetch p_cursor into v_dummy;
    end if;
end;
/

Agora crie o procedimento que sempre chamará trace, mas não necessariamente gastará tempo avaliando os argumentos.
create or replace procedure lazily_trace_something(some_number in number) is
    v_cursor sys_refcursor;
begin
    open v_cursor for select sleep(some_number) from dual;
    trace_something(v_cursor);
end;
/

Por padrão, está fazendo o trabalho e é lento:
--Takes 2 seconds to run:
begin
    lazily_trace_something(2);
end;
/

Mas quando você altera DO_I_HAVE_TO_TRACE para retornar false o procedimento é rápido, embora esteja passando um argumento lento.
create or replace function do_i_have_to_trace return boolean is
begin
    return false;
end;
/

--Runs in 0 seconds.
begin
    lazily_trace_something(2);
end;
/

Outras opções


A compilação condicional é mais tradicionalmente usada para habilitar ou desabilitar a instrumentação. Por exemplo:
create or replace package constants is
    c_is_trace_enabled constant boolean := false;
end;
/

declare
    v_dummy number;
begin
    $if constants.c_is_trace_enabled $then
        v_dummy := sleep(1);
        This line of code does not even need to be valid!
        (Until you change the constant anyway)
    $else
        null;
    $end
end;
/

Você também pode querer reconsiderar o SQL dinâmico. O estilo de programação e um pouco de açúcar sintático podem fazer uma grande diferença aqui. Em suma, a sintaxe de cotação alternativa e os modelos simples podem tornar o SQL dinâmico muito mais legível. Para mais detalhes, veja minha postagem aqui .

Passando dados genéricos


Os tipos ANY podem ser usados ​​para armazenar e transmitir qualquer tipo de dados imaginável. Infelizmente, não há tipo de dados nativo para cada tipo de linha. Você precisará criar um TYPE para cada tabela. Esses tipos personalizados são muito simples para que a etapa possa ser automatizada, se necessário.
create table some_table(a number, b number);
create or replace type some_table_type is object(a number, b number);

declare
    a_rowtype_variable some_table_type;
    v_anydata anydata;
    v_cursor sys_refcursor;
begin
    a_rowtype_variable := some_table_type(1,2);
    v_anydata := anydata.ConvertObject(a_rowtype_variable);
    open v_cursor for select v_anydata from dual;
    trace_something(v_cursor);
end;
/