plsql
La gestione delle eccezioni
Ricerca…
introduzione
Oracle produce una varietà di eccezioni. Potresti essere sorpreso di quanto possa essere noioso interrompere il tuo codice con un messaggio poco chiaro. Per migliorare la capacità del codice PL / SQL di risolverlo facilmente è necessario gestire le eccezioni al livello più basso. Non nascondere mai un'eccezione "sotto il tappeto", a meno che tu non sia qui per mantenere il tuo pezzo di codice solo per te e per nessun altro da mantenere.
Gli errori predefiniti .
La gestione delle eccezioni
Cos'è un'eccezione?
Eccezione in PL / SQL è un errore creato durante l'esecuzione di un programma.
Abbiamo tre tipi di eccezioni:
- Eccezioni definite internamente
- Eccezioni predefinite
- Eccezioni definite dall'utente
Cos'è una gestione delle eccezioni?
La gestione delle eccezioni è una possibilità per mantenere il nostro programma in esecuzione anche se compaiono errori di runtime risultanti, ad esempio, da errori di codifica, guasti hardware. Evitiamo di uscire bruscamente.
Sintassi
La sintassi generale per la sezione delle eccezioni:
declare
declaration Section
begin
some statements
exception
when exception_one then
do something
when exception_two then
do something
when exception_three then
do something
when others then
do something
end;
Una sezione di eccezione deve trovarsi alla fine del blocco PL / SQL. PL / SQL ci dà l'opportunità di annidare i blocchi, quindi ogni blocco può avere una propria sezione di eccezione, ad esempio:
create or replace procedure nested_blocks
is
begin
some statements
begin
some statements
exception
when exception_one then
do something
end;
exception
when exception_two then
do something
end;
Se verrà sollevata un'eccezione nel blocco nidificato, dovrebbe essere gestita nella sezione delle eccezioni interne, ma se la sezione delle eccezioni interne non gestisce questa eccezione, questa eccezione andrà alla sezione delle eccezioni del blocco esterno.
Eccezioni definite internamente
Un'eccezione definita internamente non ha un nome, ma ha un proprio codice.
Quando usarlo?
Se si è certi che l'operazione del proprio database potrebbe sollevare eccezioni specifiche per quelli che non hanno nomi, è possibile fornire loro nomi in modo che sia possibile scrivere gestori di eccezioni specifici per essi. Altrimenti, puoi usarli solo con others
gestori di eccezioni.
Sintassi
declare
my_name_exc exception;
pragma exception_init(my_name_exc,-37);
begin
...
exception
when my_name_exc then
do something
end;
my_name_exc exception;
questa è la dichiarazione del nome dell'eccezione.
pragma exception_init(my_name_exc,-37);
assegnare un nome al codice di errore dell'eccezione definita internamente.
Esempio
Abbiamo un emp_id che è una chiave primaria nella tabella emp e una chiave esterna nella tabella dept. Se proviamo a rimuovere emp_id quando ha dei record figli, verrà generata un'eccezione con il codice -2292.
create or replace procedure remove_employee
is
emp_exception exception;
pragma exception_init(emp_exception,-2292);
begin
delete from emp where emp_id = 3;
exception
when emp_exception then
dbms_output.put_line('You can not do that!');
end;
/
La documentazione Oracle dice: "Un'eccezione definita internamente con un nome dichiarato dall'utente è ancora un'eccezione definita internamente, non un'eccezione definita dall'utente."
Eccezioni predefinite
Le eccezioni predefinite sono eccezioni definite internamente ma hanno nomi. Il database Oracle aumenta automaticamente questo tipo di eccezioni.
Esempio
create or replace procedure insert_emp
is
begin
insert into emp (emp_id, ename) values ('1','Jon');
exception
when dup_val_on_index then
dbms_output.put_line('Duplicate value on index!');
end;
/
Di seguito sono riportati esempi di eccezioni con i relativi codici:
Nome dell'eccezione | Codice di errore |
---|---|
NESSUN DATO TROVATO | -1403 |
ACCESS_INTO_NULL | -6530 |
CASE_NOT_FOUND | -6592 |
ROWTYPE_MISMATCH | -6504 |
TOO_MANY_ROWS | -1422 |
ZERO_DIVIDE | -1476 |
Elenco completo dei nomi delle eccezioni e dei loro codici sul sito Web Oracle.
Eccezioni definite dall'utente
Come suggerisce il nome, le eccezioni definite dall'utente vengono create dagli utenti. Se vuoi creare la tua eccezione devi:
- Dichiara l'eccezione
- Sollevalo dal tuo programma
- Crea un gestore di eccezioni adatto per catturarlo.
Esempio
Voglio aggiornare tutti gli stipendi dei lavoratori. Ma se non ci sono lavoratori, sollevare un'eccezione.
create or replace procedure update_salary
is
no_workers exception;
v_counter number := 0;
begin
select count(*) into v_counter from emp;
if v_counter = 0 then
raise no_workers;
else
update emp set salary = 3000;
end if;
exception
when no_workers then
raise_application_error(-20991,'We don''t have workers!');
end;
/
Cosa significa raise
?
Le eccezioni vengono sollevate automaticamente dal server del database quando ce n'è bisogno, ma se lo desideri, puoi sollevare esplicitamente qualsiasi eccezione usando raise
.
Procedura raise_application_error(error_number,error_message);
- numero_errore deve essere compreso tra -20000 e -20999
- messaggio error_message da visualizzare quando si verifica un errore.
Definisci l'eccezione personalizzata, alzala e scopri da dove proviene
Per illustrare questo, ecco una funzione che ha 3 diversi comportamenti "sbagliati"
- il parametro è completamente stupido: usiamo un'espressione definita dall'utente
- il parametro ha un errore di battitura:
NO_DATA_FOUND
errore standardNO_DATA_FOUND
Oracle - un altro caso, ma non gestito
Sentiti libero di adattarlo ai tuoi standard:
DECLARE
this_is_not_acceptable EXCEPTION;
PRAGMA EXCEPTION_INIT(this_is_not_acceptable, -20077);
g_err varchar2 (200) := 'to-be-defined';
w_schema all_tables.OWNER%Type;
PROCEDURE get_schema( p_table in Varchar2, p_schema out Varchar2)
Is
w_err varchar2 (200) := 'to-be-defined';
BEGIN
w_err := 'get_schema-step-1:';
If (p_table = 'Delivery-Manager-Is-Silly') Then
raise this_is_not_acceptable;
end if;
w_err := 'get_schema-step-2:';
Select owner Into p_schema
From all_tables
where table_name like(p_table||'%');
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- handle Oracle-defined exception
dbms_output.put_line('[WARN]'||w_err||'This can happen. Check the table name you entered.');
WHEN this_is_not_acceptable THEN
-- handle your custom error
dbms_output.put_line('[WARN]'||w_err||'Please don''t make fun of the delivery manager.');
When others then
dbms_output.put_line('[ERR]'||w_err||'unhandled exception:'||sqlerrm);
raise;
END Get_schema;
BEGIN
g_err := 'Global; first call:';
get_schema('Delivery-Manager-Is-Silly', w_schema);
g_err := 'Global; second call:';
get_schema('AAA', w_schema);
g_err := 'Global; third call:';
get_schema('', w_schema);
g_err := 'Global; 4th call:';
get_schema('Can''t reach this point due to previous error.', w_schema);
EXCEPTION
When others then
dbms_output.put_line('[ERR]'||g_err||'unhandled exception:'||sqlerrm);
-- you may raise this again to the caller if error log isn't enough.
-- raise;
END;
/
Dando su un database regolare:
[WARN]get_schema-step-1:Please don't make fun of the delivery manager.
[WARN]get_schema-step-2:This can happen. Check the table name you entered.
[ERR]get_schema-step-2:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows
[ERR]Global; third call:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows
Ricorda che l'eccezione è qui per gestire casi rari . Ho visto applicazioni che hanno sollevato un'eccezione ad ogni accesso, solo per chiedere la password dell'utente, dicendo "non connesso" ... così tanto spreco di calcolo.
Gestione delle eccezioni degli errori di connessione
Ogni errore Oracle standard è associato a un numero di errore. È importante prevedere cosa potrebbe andare storto nel codice. Qui per una connessione a un altro database, può essere:
-
-28000
account è bloccato -
-28001
password scaduta -
-28002
periodo di grazia -
-1017
utente / password errati
Ecco un modo per testare cosa non va con l'utente utilizzato dal collegamento al database:
declare
v_dummy number;
begin
-- testing db link
execute immediate 'select COUNT(1) from [email protected]' into v_dummy ;
-- if we get here, exception wasn't raised: display COUNT's result
dbms_output.put_line(v_dummy||' users on PASS db');
EXCEPTION
-- exception can be referred by their name in the predefined Oracle's list
When LOGIN_DENIED
then
dbms_output.put_line('ORA-1017 / USERNAME OR PASSWORD INVALID, TRY AGAIN');
When Others
then
-- or referred by their number: stored automatically in reserved variable SQLCODE
If SQLCODE = '-2019'
Then
dbms_output.put_line('ORA-2019 / Invalid db_link name');
Elsif SQLCODE = '-1035'
Then
dbms_output.put_line('ORA-1035 / DATABASE IS ON RESTRICTED SESSION, CONTACT YOUR DBA');
Elsif SQLCODE = '-28000'
Then
dbms_output.put_line('ORA-28000 / ACCOUNT IS LOCKED. CONTACT YOUR DBA');
Elsif SQLCODE = '-28001'
Then
dbms_output.put_line('ORA-28001 / PASSWORD EXPIRED. CONTACT YOUR DBA FOR CHANGE');
Elsif SQLCODE = '-28002'
Then
dbms_output.put_line('ORA-28002 / PASSWORD IS EXPIRED, CHANGED IT');
Else
-- and if it's not one of the exception you expected
dbms_output.put_line('Exception not specifically handled');
dbms_output.put_line('Oracle Said'||SQLCODE||':'||SQLERRM);
End if;
END;
/