Acerca de admin

Tras más de 20 años trabajando con tecnologías Oracle, me decidí a recopilar en un Blog algunas de las cosillas útiles para el día a día.

Rotar el listener sin pararlo

Hoy vamos a ver una entrada de dummy pero de mucha utilidad.

Habitualmente, el log del listener crece de manera descontrolada y solemos tener problemas a la hora de borrarlo. No podemos detener el listener,por que cortaríamos el servicio, y tampoco podemos borrar el fichero del log por que está en uso.
¿Que hacemos entonces?

La solución es bien sencilla, simplemente dejamos de logar, vaciamos y volveos a logar.
Lo primero que hemos de hacer es conectarnos desde linea de comandos al listener, lo que vamos ha hacer es:

  • Comprobar si estamos logando
  • Mirar cual es el log
  • Mirar cual es el directorio de trazas

La salida de los comandos será:

oracle@server : lsnrctl
LSNRCTL> show log_status
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
LISTENER parameter "log_status" set to ON
The command completed successfully
LSNRCTL> show log_file
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
LISTENER parameter "log_file" set to /u01/app/oracle/diag/tnslsnr/server/listener/alert/log.xml
The command completed successfully
LSNRCTL> show trc_directory
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
LISTENER parameter "trc_directory" set to /u01/app/oracle/diag/tnslsnr/server/listener/trace
The command completed successfully
LSNRCTL> set log_status off

En otra ventana, iremos al directorio de tazas y borraremos o moveremos las trazas que nos molestan
Una vez eliminados, solamente hemos de volver a activar el log

LSNRCTL> set log_status on;
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
LISTENER parameter "log_status" set to ON
The command completed successfully
LSNRCTL> show log_status
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
LISTENER parameter "log_status" set to ON
The command completed successfully
LSNRCTL>

Mover tablas con subparticiones

Supongamos que tenemos una tabla llamada AGENTE , esta tabla agente está particionada por número de agente, y a su vez, particionada por trimestre.
Así pues tendremos que la estructura es mas o menos
PARTICIONADO

Y queremos mover estas particiones a un nuevo tablespace (TS_NEW). Lo primero que se nos pasa por la cabeza es el ejecutar:

alter table PROPIETARIO.AGENTE move partition  AG1  tablespace TS_NEW;

Pero Oracle nos devolverá el error

Error at line 1
ORA-14257: no se puede mover una partición que no sea de Rango, Lista, Sistema o Hash

Lo primero que nos viene a la cabeza es el preguntarnos donde está el error e ir a comprobar que tipo de partición tenemos, sin embargo, si aplicamos un poco el sentido común, veremos que lo que nos está indicando este error es que debemos de mover nuestra tabla subparticion a subparticion .
La sintaxsis correcta será:

alter table PROPIETARIO.AGENTE 
	move subpartition  PRIMER1
			tablespace TS_NEW;
alter table PROPIETARIO.AGENTE 
	move subpartition  PRIMER2 
				tablespace TS_NEW;
alter table PROPIETARIO.AGENTE
		move subpartition
			PRIMER3 tablespace TS_NEW;

Esta tarea puede ser realmente tediosa si nuestra tabla tiene un gran número de particiones y subparticiones, con lo que, lo mejor será hacer un script para moverla.
Lo primero que ha de hacerse en estos casos, es guardar la manera de volver a la situacion actual, esto lo conseguiremos con la salida del comando

select 'alter table'||
	    table_owner||
		'.'||
		table_name||
		' move subpartition '
		||subpartition_name||
		' tablespace '
		|| tablespace_name||
		' ;'
     		from  DBA_TAB_SUBPARTITIONS
   			where table_name='TABLA'

Una vez hemos guardado esta salida, podemos pasar a generar el script que nos moverá todas las subparticiones al nuevo tablespace TS_NEW

select 'alter table '
		||table_owner||
		'.'
		||table_name||
		' move subpartition '
		||subpartition_name||
		' tablespace 
		TS_NEW;' 
		    from  DBA_TAB_SUBPARTITIONS 
			 where table_name='TABLA'

Como siempre, mas información en la documentación de Oracle

Escribir la salida de un sql en un fichero con UTL_FILE

Vamos con otra entrada básica para dummies.

Supongamos que queremos hacer implantar algún tipo de sonda que nos haga una pregunta a la base de datos y nos deje el resultado en un directorio.
Vamos a crear un pequeño procedimiento que, a modo de ejemplo nos saque algunos parámetros del v$session y nos lo deje en un directorio previamente definido llamado SONDA

CREATE OR REPLACE PROCEDURE proc_a_file AS
     fichero utl_file.file_type;
     nombre_fichero  VARCHAR2(255);
     linea_resul  VARCHAR2(255);
        BEGIN
  -- Definimos el nombre del log de salida
     select  'sonda_'||
              to_char(TO_CHAR(sysdate, 'YYYYMMDDHHmiss'))||
             '.log'
              into nombre_fichero  from dual  ;
  -- Abrimos fichero      
       fichero := utl_file.fopen('SONDA', nombre_fichero, 'A');
  -- Añadimos encabezado   
           UTL_FILE.PUT_LINE ( fichero ,'SID, SERIAL,TERMINAL,OSUSER');
  -- Lanzamos consulta        
                     FOR ciclo IN (
                         SELECT
                              select sid SID,
                              serial#  SERIAL,
                              terminal TEMINAL,
                              osuser  USER  
                         from v$session
                               )
                  LOOP  --Bucle de scritura de datos 
                 UTL_FILE.PUT_LINE ( fichero ,ciclo.SID||
                                              chr(44)|| 
                                             ciclo.SERIAL||
                                              chr(44)|| 
                                            ciclo.TERMINAL||
                                            chr(44)||
                                            ciclo.USER);
                 END LOOP;         
-- Limpiamos y cerramos
          utl_file.fflush(fichero);
        utl_file.fclose(fichero);
-- Excepciones de error en el alert.log
    EXCEPTION
    WHEN UTL_FILE.WRITE_ERROR THEN
    dbms_system.ksdwrt(2, 'ORA-XXXX  Error en procedure proc_a_file escrbiendo en fichero de log.');
    WHEN others THEN
       dbms_system.ksdwrt(2, 'ORA-XXXX  Error genérico en procedure   proc_a_file. '||SQLERRM);
      END proc_a_file; -- En del procedure

Ahora ya podemos lanzar nuestro procedimiento, bien desde el código de aplicación, cron, task manager, trigger o desde el lugar que deseemos

Ejecutar un sql como otro usuario

Hoy vamos a volver a las entradas de dummies.

Muchas veces, tenemos que ejecutar consultas desde sqlplus como un usuario de aplicación del que desconocemos su contraseña.
Nosotros contamos con privilegios de administrador, pero , lo que necesitamos es entrar con el usuario de aplicacion «fotos»

La solución es extremadamente sencilla

[oracle@server] [$sqlplus "/as sysdba"
SQL*Plus: Release 11.2.0.2.0 Production on Mar Abr 1 21:15:45 2014
Copyright (c) 1982, 2011, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
SQL> alter session set current_schema=FOTOS;
Session altered.
SQL>

					

Tabla noexp$ en oracle

Hoy vamos ha hacer una de esas entradas «para guardar», su merito es totalmente de un compañero de trabajo, que me ha contado esta mañana la existencia de esta tabla.
Oracle tiene una tabla llamada noexp$ donde puedes ubicar los objetos de los que no quieras que se hagan exports.

Esta tabla tiene 3 campos, el OWNER del objeto, el OWNER del objeto y el tipo de objeto que es.

SQL> desc NOEXP$
Name Null? Type
--------------------- -------- ------------
 OWNER                 NOT NULL VARCHAR2(30)
NAME                  NOT NULL VARCHAR2(30)
OBJ_TYPE              NOT NULL NUMBER

Si queremos exportar la tabla PASS del esquema FOTOS, ejecutaremos el comando :

[oracle@test] [$expdp system/***** tables=FOTOS.PASS file=nada.dmp directory=backup
Export: Release 11.2.0.2.0 - Production on Lun Abr 14 16:38:48 2014
Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
Legacy Mode Active due to the following parameters:
Legacy Mode Parameter: "file=nada.dmp" Location: Command Line, Replaced with: "dumpfile=nada.dmp"
Legacy Mode has set reuse_dumpfiles=true parameter.
Starting "SYSTEM"."SYS_EXPORT_TABLE_01":  system/******** tables=FOTOS.PASS dumpfile=nada.dmp directory=backup reuse_dumpfiles=true
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 1024 KB
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/INDEX/INDEX
Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type TABLE_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
. . exported "FOTOS"."PASS"                              6.796 KB      27 rows
Master table "SYSTEM"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYSTEM.SYS_EXPORT_TABLE_01 is:
  /vgbackup/backup/oracle/nada.dmp
Job "SYSTEM"."SYS_EXPORT_TABLE_01" successfully completed at 21:39:07

Ha funcionado correctamente, pero , y si no queremos que se pueda exportar esta tabla?

Lo primero que tendremos que hacer es ver el tipo de objeto que es esa tabla. Para ello ejecutaremos la consulta

SQL> select name,type# from obj$ where name = 'PASS';
NAME                                TYPE#
------------------------------ ----------
PASS                                    2

Una vez sabemos que es de tipo «2», la introduciremos en la tabla «noexp$» (como sys)

insert into NOEXP$ values ('FOTOS','PASS','2');

Que ocurre si intentas hacer un export de esa tabla??

[oracle@test [$expdp system/**** tables=FOTOS.PASS file=nada.dmp directory=backup
Export: Release 11.2.0.2.0 - Production on Lun Abr 14 16:42:03 2014
Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
Legacy Mode Active due to the following parameters:
Legacy Mode Parameter: "file=nada.dmp" Location: Command Line, Replaced with: "dumpfile=nada.dmp"
Legacy Mode has set reuse_dumpfiles=true parameter.
Starting "SYSTEM"."SYS_EXPORT_TABLE_01":  system/******** tables=FOTOS.PASS dumpfile=nada.dmp directory=backup reuse_dumpfiles=true
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 0 KB
ORA-39166: Object FOTOS.PASS was not found.
ORA-31655: no data or metadata objects selected for job
Job "SYSTEM"."SYS_EXPORT_TABLE_01" completed with 2 error(s) at 16:42:07

Como vemos, el export (expdp) no encuentra la tabla, con lo que no puede llevar a cabo la exportación.
Hay que tener mucho cuidado ya que, lo que no está exportando es la tabla, no los contenidos, con lo que , en nuestro caso, un export full de la base de datos haría que la aplicación no funcionase ya que ,no existe la tabla de passwords ( ni la estructura ni los datos)

Más información, como siempre en metalink en la nota «OERR: EXP 55 %s.%s is marked not exportable (Doc ID 47991.1)»