Doven evaluering kan (delvist) implementeres ved hjælp af ref-markører, betinget kompilering eller udføres med det samme. ANYDATA-typen kan bruges til at videregive generiske data.
Ref markør
Ref-markører kan åbnes med en statisk SQL-sætning, sendes som argumenter og vil ikke udføres, før de er nødvendige.
Selvom dette bogstaveligt talt besvarer dit spørgsmål om doven evaluering, er jeg ikke sikker på, om det virkelig er praktisk. Dette er ikke den tilsigtede brug af ref markører. Og det er måske ikke praktisk at skulle tilføje SQL til alting.
Først, for at bevise, at den langsomme funktion kører, skal du oprette en funktion, der simpelthen sover i et par sekunder:
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;
/
Opret en funktion for at bestemme, om evaluering er nødvendig:
create or replace function do_i_have_to_trace return boolean is
begin
return true;
end;
/
Denne funktion kan udføre arbejdet ved at udføre SQL-sætningen. SQL-sætningen skal returnere noget, selvom du måske ikke ønsker en returværdi.
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;
/
Opret nu proceduren, der altid vil kalde sporing, men som ikke nødvendigvis vil bruge tid på at evaluere argumenterne.
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;
/
Som standard udfører den arbejdet og er langsom:
--Takes 2 seconds to run:
begin
lazily_trace_something(2);
end;
/
Men når du ændrer DO_I_HAVE_TO_TRACE
for at returnere falsk er proceduren hurtig, selvom den sender et langsomt argument.
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;
/
Andre muligheder
Betinget kompilering bruges mere traditionelt til at aktivere eller deaktivere instrumentering. For eksempel:
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;
/
Det kan også være en god idé at genoverveje dynamisk SQL. Programmeringsstil og noget syntaktisk sukker kan gøre en stor forskel her. Kort sagt kan den alternative citatsyntaks og simple skabeloner gøre dynamisk SQL meget mere læsbar. For flere detaljer se mit indlæg her .
Videregivelse af generiske data
Alle typer kan bruges til at gemme og videregive enhver tænkelig datatype. Desværre er der ingen indbygget datatype for hver rækketype. Du skal oprette en TYPE for hver tabel. Disse brugerdefinerede typer er meget enkle, så det trin kan automatiseres, hvis det er nødvendigt.
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;
/