Personalize exceções PL/SQL no Oracle
-
21-09-2019 - |
Pergunta
Freqüentemente me vi fazendo algumas funções para inserir/excluir/atualizar em uma ou mais tabelas e vi algumas exceções esperadas foram cuidadas, como no_data_found
, dupl_val_on_index
, etc. Para uma inserção como esta:
create or replace FUNCTION "INSERT_PRODUCTS" (
a_supplier_id IN FORNECEDOR.ID_FORNECEDOR%TYPE,
a_prodArray IN OUT PRODTABLE
)
RETURN NUMBER IS
v_error_code NUMBER;
v_error_message VARCHAR2(255);
v_result NUMBER:= 0;
v_prod_id PRODUTO.ID_PROD%TYPE;
v_supplier FORNECEDOR%ROWTYPE;
v_prodInserted PROD_OBJ;
newList prodtable := prodtable();
BEGIN
SELECT FORNEC_OBJ(ID_FORNECEDOR,NOME_FORNECEDOR,MORADA,ARMAZEM,EMAIL,TLF,TLM,FAX) into v_supplier from fornecedor where id_fornecedor = a_supplier_id;
FOR i IN a_prodArray.FIRST .. a_prodArray.LAST LOOP
INSERT INTO PRODUTO (PRODUTO.ID_PROD,PRODUTO.NOME_PROD,PRODUTO.PREC_COMPRA_PROD,PRODUTO.IVA_PROD,PRODUTO.PREC_VENDA_PROD,PRODUTO.QTD_STOCK_PROD,PRODUTO.QTD_STOCK_MIN_PROD)
VALUES (S_PRODUTO.nextval,a_prodArray(i).NOME_PROD,a_prodArray(i).PREC_COMPRA_PROD,a_prodArray(i).IVA_PROD,NULL,NULL,NULL);
/* If the above insert didn't failed, we can insert in weak entity PROD_FORNECIDO. */
SELECT ID_PROD into v_prod_id from PRODUTO where NOME_PROD = a_prodArray(i).NOME_PROD;
INSERT INTO PROD_FORNECIDO VALUES (a_supplier_id, v_prod_id,a_prodArray(i).PREC_COMPRA_PROD);
SELECT PROD_OBJ(ID_PROD,NOME_PROD,PREC_COMPRA_PROD,PREC_VENDA_PROD,QTD_STOCK_PROD,QTD_STOCK_MIN_PROD,IVA_PROD) into v_prodInserted from PRODUTO where ID_PROD= v_prod_id;
a_prodarray(i).ID_PROD := v_prod_id;
END LOOP;
INSERT INTO FORNECPRODS VALUES (a_supplier_id,v_supplier, a_prodarray);
v_result:= 1;
RETURN v_result;
COMMIT;
Exception
When no_data_found then
v_error_code := 0;
v_error_message:= 'Insert Products: One of selects returned nothing';
Insert Into errors Values (v_error_code,v_error_message, systimestamp);
RETURN v_result;
When others Then
ROLLBACK;
v_error_code := SQLCODE;
v_error_message:=substr(SQLERRM,1,50);
Insert Into errors Values (v_error_code,'Error inserting products list',systimestamp);
RETURN v_result;
END;
Gostaria de personalizar mais minhas exceções ou fazer um bloco de exceção para cada seleção/inserção. Isso é possível ou correto?
Nesse caso, poderia me mostrar algum código com exceções importantes sendo jogadas por essa função?
Solução
Na seção de exceção; Você pode aumentar o erro do aplicativo ou retornar 0 com a explicação do código de erro. É sobre sua escolha.
Se você deseja registrar seus erros na seção de exceção (ou na seção principal), escreva seu próprio procedimento de log com transação autônoma. Portanto, seu mecanismo de registro não é afetado pela confirmação ou reversão da sua transação principal. (Vejo: http://www.dba-oracle.com/t_autonomous_transaction.htm)
Outro mecanismo de registro (log de erro DML) no Oracle 10gr2 (e acima) é a cláusula de erros de log (consulte: http://www.oracle-base.com/articles/10g/dmlerrorlogging_10gr2.php).
Outras dicas
Se você deseja apenas substituir sua própria mensagem de erro, existe RAISE_APPLICATION_ERROR
...
When no_data_found then
RAISE_APPLICATION_ERROR(-20000
, 'Insert Products: One of selects returned nothing';
, true);
O terceiro parâmetro retorna o erro original e o seu personalizado.
O Oracle também nos dá a opção de definir nossas exceções. Isso pode ser útil se quisermos passar a exceção a um programa de chamada ...
Declare
no_product_found exception;
Begin
....
When no_data_found then
raise no_product_found;
Isso seria mais eficaz se definirmos a exceção No_product_found em uma especificação de pacote, onde poderia ser referenciada por unidades de programa externas.
Além disso, o Oracle fornece a Pragma init_exception, que nos permite associar números de erros do Oracle às nossas exceções personalizadas. Infelizmente, não podemos sobrecarregar os números de erros que o Oracle já definiu (por exemplo, não podemos criar nossas próprias exceções para o ORA-1403, que já está coberto pela exceção No_Data_Found). Descubra mais.