Errores ORA-29279 usando UTL_SMTP

Con la implementacion del Fine Grained Acess en la gestión de conexiones de la base de datos,el DBA acaba siendo en muchos casos el punto de entrada de la resolucion de errores que nada tienen que ver con el motor de la base de datos.
Uno de estos errores muy comunes son los ORA-29279 usando UTL_SMTP

Afortunadamente, Oracle es muy claro al respecto.
Los errores ORA-29279 no son un error del motor, sino que nos transmite os escalan el error que dando el servidor de correo


Contact your SMTP administrator for additional assistance as this solution may require your e-mail administrator to make the necessary changes.

Así que, claro y en botella.
Mas info en :

  • ORA-29279 SMTP: 554 Using Utl_smtp To Send Email (Doc ID 1471828.1)
  • Document 604763.1 – Check SMTP Server Availability for ORA-29278 or ORA-29279 errors using UTL_SMTP to Send Email
  • ORA-2427 con el paquete SMTP

ORA-08189: no se puede realizar flashback

Hoy vamos a ver otra entrada para dummies.
Un error tremendamente sencillo que puede darnos algún susto, pero que hará que todo se quede en eso, en un susto.

Supongamos que queremos volver una tabla de nuestra base de datos ha hace 2 horas , lo más inmediato es intentar hacer:

FLASHBACK TABLE OWNER.TABLA 
  TO TIMESTAMP (SYSTIMESTAMP - INTERVAL '120' minute);

Pero, nos encontramos con el error:

Error at line 1
ORA-08189: no se puede realizar flashback en la tabla porque el movimiento de filas no está activado

Lo primero que nos viene a la cabeza es pensar que no vamos a poder ser capaces de recupera la tabla, pero, realmente, cuando obtenemos este error (o en Ingles)
ORA-08189: cannot flashback the table because row movement is not enabled
no está todo perdido, simplemente nos está indicando que no tenemos la opcion de «row movement» para poder llevar a cabo esta actualizacion.

Para solventar este problema haremos


ALTER TABLE OWNER.TABLA ENABLE ROW MOVEMENT;

Con este sencillo comando ya podremos ejecutar nuestro flashback… TO TIMESTAMP sin recibir alertas de error

ORA-24247 con el paquete STMP

Hoy vamos a ver como resolver errores ORA-24247 en la version 11g . Aunque desde aquí siempre hemos mantenido (y mantendremos) que la base de datos no debería ser la responsable de enviar correos o conectarse a «vete a saber donde» hay entornos en los que nos vemos obligados a ello.

¿Que ocurre si nos encontramos con un error de este tipo ?

error-ora-ORA-24247.jpg

ERROR at line 1:
ORA-24247: network access denied by access control list (ACL)
ORA-06512: at "SYS.UTL_TCP", line 17
ORA-06512: at "SYS.UTL_TCP", line 246
ORA-06512: at "SYS.UTL_SMTP", line 115
ORA-06512: at "SYS.UTL_SMTP", line 138
ORA-06512: at "XXX", line 36
ORA-06512: at line 1

Este error es debido a que no contamos con una ACl para el servicio de red, las ACLs son un elemento nuevo de Oracle 11g (11.1.0.6) que establece un filtrado mas detallado (fine-grained access) y que controla el acceso a algunos paquetes como el UTL_SMTP o el UTL_HTTP.

¿como lo solicionamos?

Sencillamente tenemos que crear una ACL que nos permita acceder al puerto 25 de nuestro servidor de correo.
En este caso lo haremos para

  • SMTP Server 127.0.0.1 (localhost de la BBDD)
  • Puerto 25 ( puerto estandard de correo)
  • usuarios Usuario1 y usuario2

Así pues , ejecutaremos :

begin
--creamos la ACL
DBMS_NETWORK_ACL_ADMIN.CREATE_ACL
   (acl => 'send_mail.xml',
   description => '
   send_mail ACL',
   principal => 'USUARIO1',
   is_grant => true, 
   privilege => 'connect');
-- Asignamos privilegios  al usuario elegido 
DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(
   acl => 'send_mail.xml',
   principal => 'USUARIO1',
   is_grant  => true,
   privilege => 'connect');
DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(
   acl => 'send_mail.xml',
   principal => 'USUARIO1',
   is_grant  => true,
   privilege => 'resolve');
-- Asignamos provilegios  al usuario elegido 
DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(
   acl => 'send_mail.xml',
   principal => 'USUARIO2',
   is_grant  => true,
   privilege => 'connect');
--Asignamos recursos 
 dbms_network_acl_admin.assign_acl (
   acl => 'send_mail.xm',
   host => '127.0.0.1',
   lower_port => 25,
  upper_port => 25);
END;
/
COMMIT;

Si queremos ver las ACL creadas

SELECT * FROM dba_network_acls;

Y los privilegios de cada una de ellas

SELECT acl
      ,principal
      ,privilege
      ,is_grant
      ,invert
      ,start_date
      ,end_date
  FROM dba_network_acl_privileges;

Como siempre , mas información en oracle en las notas:

ORA-29786 eliminando un Diskgroup

Hoy vamos a ver un error que puede ser bastante común si creamos las cosas a mano » a la antigua usanza».

Veamos algo que puede ocurrirnos cuando intentamos eliminar un diskgroup en nuestro ASM

[oracle@test]$ sqlplus "/as sysasm"
SQL*Plus: Release 11.2.0.3.0 Production on Fri Apr 09 21:10:38 2015
Copyright (c) 1982, 2011, Oracle.  All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Automatic Storage Management option
SQL> DROP DISKGROUP TEMP INCLUDING CONTENTS;
DROP DISKGROUP TEMP INCLUDING CONTENTS
*ERROR at line 1:
ORA-15039: diskgroup not dropped
ORA-29786: SIHA attribute GET failed with error [Attribute 'SPFILE' sts[200]lsts[0]]

Este error nos va a dar tanto si está montado, desmontado, tiene ficheros, o está vacío, y , el problema es el modo de creacion.

Desde la versión 11gr2 el ASM es un recurso mas del CRS, por lo cual, para poder llevar a cabo determinadas operaciones como create/drop diskgroup, create pfile/spfile es necesario que el ASM esté registrado como un recurso del cluster.

La solucion para poder llevar a cabo estas acciones es añadir el ASM al repositorio del cluster

srvctl add asm -h
Adds an ASM configuration to be managed by Oracle Restart.
Usage: srvctl add asm [-l ] [-p ] [-d ]
    -l            Listener name
    -p               Server parameter file path
    -d       ASM diskgroup discovery string
    -h                       Print usage


srvctl add asm  -p $GRID_HOME/dbs/init+ASM.ora 
srvctl status asm

Más informacion como siempre en metalink en la nota

Capturar errores de usuario en la base de datos

Hoy vamos a ver como facilitarnos un poco el control del código de aplicación de la base de datos.

En muchas ocasiones, los desarrolladores no llevan a cabo correctamente la captura de errores , lo que produce una serie quejas «no me va y no me da error».
Para lidiar con estas situaciones podemos crear un pequeño trigger que registre en la base de datos que y quien genera errores en la base de datos, para poder seguirlos y depurar estos errores.

Vamos a suponer que:

  • Tenemos un tablespace específico llamado CONTROL donde guardaremos nuestros datos
  • Tenemos un usuario llamado CONTROL que será el propietario del código

Primero crearemos la tabla que contendrán los errores:

-- Creamos la tabla 
create table CONTROL.oraerror (
identificador   NUMBER,
FECHA           DATE,
ESQUEMA         VARCHAR2(30),
USUARIO         VARCHAR2(50),
SQL_ID          VARCHAR2 (13) DEFAULT NULL,
SQL_HASH_VALUE  NUMBER DEFAULT NULL,
err_nr          NUMBER(10),
err_msg         VARCHAR2(4000),
stmt            CLOB
) TABLESPACE CONTROL;

--
-- Creamos una secuencia para el oraerror
create sequence CONTROL.oraerror_seq
start with 1
increment by 1
minvalue 1
nomaxvalue
nocache
nocycle;

Y después crearemos nuestro trigguer

CREATE OR REPLACE TRIGGER CONTROL.after_error
 AFTER SERVERERROR ON DATABASE
 DECLARE
 id             NUMBER;
 vSerial        NUMBER DEFAULT NULL;
 ESQUEMA        VARCHAR2(30);
USUARIO         VARCHAR2(50);
 SQL_ID         VARCHAR2 (13) DEFAULT NULL;
 SQL_HASH_VALUE NUMBER DEFAULT NULL;
  sql_text      ORA_NAME_LIST_T;
 v_stmt         CLOB;
 n              NUMBER;
 vsid           NUMBER DEFAULT NULL;
BEGIN
 -- BUscamos ID 
SELECT dbms_debug_jdwp.current_session_serial serial# INTO vSerial 
      FROM DUAL;
SELECT oraerror_seq.nextval,SYS_CONTEXT ('USERENV', 'sid') INTO  id, vsid
     FROM dual;
SELECT  SQL_ID, SQL_HASH_VALUE,USERNAME,OSUSER INTO SQL_ID, SQL_HASH_VALUE,ESQUEMA,USUARIO
   FROM sys.v_$session   WHERE sid = vsid AND serial# = vSerial;
n:= ora_sql_txt(sql_text);

IF n >= 1
 THEN
 FOR i IN 1..n LOOP
 v_stmt := v_stmt || sql_text(i);
 END LOOP;
END IF;
--
 FOR n IN 1..ora_server_error_depth LOOP
      INSERT  /*+ APPEND */ 
      INTO CONTROL.oraerror VALUES(id, sysdate, ESQUEMA, USUARIO, SQL_ID,SQL_HASH_VALUE,  ora_server_error(n), ora_server_error_msg(n), v_stmt);
  END LOOP;
 --
END ;

Con esto tendrémos en nuestra tabla todos los errores que dela base de datos.
Hay que tener en cuenta que, muchos de los errores pueden ser correctos, como los errores :

  • ORA-01017: nombre de usuario/contraseña no válidos; conexión denegada
  • ORA-00001: unique constraint (XXXX) violated (error asumible en cargas masivas)
  • ORA-03113: end-of-file on communication channel ORA-03113: end-of-file on communication channel

Con lo que habrá que seguirlos con cuidado y ver en que caso son reprochables o asumibles