miércoles, 30 de abril de 2025

Auditorias de Oracle (DBMS_FGA)

 Objetivos:











 Describir las Auditorias de Oracle.
 Conocer los Procesos ADD_POLICYDROP_POLICY, ENABLE_POLICY y DISABLE_POLICY del paquete DBMS_FGA de SYS.
 Ver ejemplos prácticos.
_______________________________________________________________________
Políticas de Auditoria de Oracle
Oracle ofrece poderosas herramientas para el rastreo de todas las transacciones y/o consultas realizadas a sus tablas, esto se puede lograr con el uso del paquete DBMS_FGA el cual proporciona procesos de seguridad y control que permiten realizar las auditorias de forma precisa y certera. Debe tener pendiente que el uso de dicho paquete requiere los privilegios de administrador, ésto debido que las auditorias permiten el acceso a informaciones sensitivas del entorno del usuario y/o la aplicación del cual opera.

_______________________________________________________________________
Paquete DBMS_FGA
A continuación el detalle de los procesos que veremos en esta publicación:
  • ADD_POLICY: Crea la política de auditoría de acuerdo a los parámetros proporcionados.

Sintaxis:  

SYS.DBMS_FGA.ADD_POLICY(
		object_schema   	IN	VARCHAR2 DEFAULT NULL, 
		object_name     	IN	VARCHAR2,
policy_name IN VARCHAR2,
audit_condition IN VARCHAR2 DEFAULT NULL,
audit_column IN VARCHAR2 DEFAULT NULL,
handler_schema IN VARCHAR2 DEFAULT NULL,
handler_module IN VARCHAR2 DEFAULT NULL,
enable IN BOOLEAN DEFAULT TRUE,
statement_types IN VARCHAR2 DEFAULT SELECT,
audit_trail IN BINARY_INTEGER DEFAULT NULL,
audit_column_opts IN BINARY_INTEGER DEFAULT ANY_COLUMNS,
policy_owner IN VARCHAR2 DEFAULT NULL
);
  • DROP_POLICY: Elimina la política de auditoria especificada.

 Sintaxis:  

SYS.DBMS_FGA.DROP_POLICY(
			   object_schema	IN	VARCHAR2, 
			   object_name		IN	VARCHAR2, 
policy_name IN VARCHAR2
);
  •  ENABLE_POLICY: Habilita la política de auditoria especificada.

 Sintaxis: 

SYS.DBMS_FGA.ENABLE_POLICY(
			   object_schema	IN	VARCHAR2 DEFAULT NULL,
object_name IN VARCHAR2,
policy_name IN VARCHAR2,
enable IN BOOLEAN DEFAULT TRUE
);
  • DISABLE_POLICY: Desactiva/deshabilita la política de auditoria especificada.

  Sintaxis: 

SYS.DBMS_FGA.DISABLE_POLICY(
				object_schema	IN	VARCHAR2,
				object_name	IN	VARCHAR2,
				policy_name	IN	VARCHAR2
			); 
_______________________________________________________________________
Ejemplo Funcional
Para nuestra prueba utilizamos la tabla EMPLOYEES del esquema HR; En caso de no contar con este esquema y/o table puede instalarlo siguiendo las instrucciones aportadas en esta publicación. Adicionalmente creamos la tabla hr.consultas_tab_employees, el procedimiento hr.prc_audit_employees y la política de auditoria.

Script Tabla hr.consultas_tab_employees: 
BEGIN
    EXECUTE IMMEDIATE   'DROP TABLE hr.consultas_tab_employees';

    EXCEPTION
        WHEN OTHERS THEN
            NULL;
END;
/

CREATE TABLE    hr.consultas_tab_employees
(
    usuario_db          VARCHAR2(30)
    , fecha             TIMESTAMP
    , query             CLOB
    , valor_consulta    VARCHAR2(500)
, terminal VARCHAR2(500)
, host VARCHAR2(500)
, ip VARCHAR2(500)
, programa VARCHAR2(500)
, usuario_os VARCHAR2(500)
, sid VARCHAR2(500)
, object_schema VARCHAR2(500)
, object_name VARCHAR2(500)
, policy_name VARCHAR2(500)
);
Script Procedimiento hr.prc_audit_employees: Notar que hacemos usado de la función  SYS_CONTEXT, puede encontrar mas información sobre ella aquí.
CREATE OR   REPLACE PROCEDURE   hr.prc_audit_employees(
                                                        object_schema VARCHAR2
                                                        , object_name VARCHAR2
                                                        , policy_name VARCHAR2
                                                      )  AS

    v_execution_user    VARCHAR2(30);
    v_execution_date    TIMESTAMP;
    v_execution_sql     CLOB;
    v_valor_consulta    VARCHAR2(500);
v_terminal_name VARCHAR2(500);
v_host_name VARCHAR2(500);
v_ip_address VARCHAR2(500);
v_program_name VARCHAR2(500);
v_os_user VARCHAR2(500);
v_sid_user VARCHAR2(500);
BEGIN v_execution_user := USER; v_execution_date := SYSTIMESTAMP; v_execution_sql := SYS_CONTEXT('USERENV','CURRENT_SQL'); v_valor_consulta := SYS_CONTEXT('USERENV','CURRENT_BIND');
v_terminal_name := SYS_CONTEXT('USERENV','TERMINAL');
v_host_name := SYS_CONTEXT('USERENV','HOST');
v_ip_address := SYS_CONTEXT('USERENV','IP_ADDRESS');
v_program_name := SYS_CONTEXT('USERENV','MODULE');
v_os_user := SYS_CONTEXT('USERENV','OS_USER');
v_sid_user := SYS_CONTEXT('USERENV','SID');
INSERT INTO hr.consultas_tab_employees ( usuario_db , fecha , query , valor_consulta , terminal , host , ip , programa , usuario_os , sid , object_schema , object_name , policy_name ) VALUES ( v_execution_user --usuario_db VARCHAR2(30) , v_execution_date --fecha TIMESTAMP , v_execution_sql --query CLOB , v_valor_consulta --valor_consulta VARCHAR2(500) , v_terminal_name --terminal VARCHAR2(500) , v_host_name --host VARCHAR2(500) , v_ip_address --ip VARCHAR2(500) , v_program_name --programa VARCHAR2(500) , v_os_user --usuario_os VARCHAR2(500) , v_sid_user --sid VARCHAR2(500) , object_schema --object_schema VARCHAR2(500) , object_name --object_name VARCHAR2(500) , policy_name --policy_name VARCHAR2(500) ); END prc_audit_employees; /
Script Auditoria AUDIT_EMPLOYEES: 
SET SERVEROUTPUT ON
BEGIN
    SYS.DBMS_FGA.DROP_POLICY(
             --Argument Name       Value               Type       In/Out
             --------------------  ----------------- ------
             object_schema    =>   'HR'              --VARCHAR2   IN
             ,object_name     =>   'EMPLOYEES'       --VARCHAR2   IN
             ,policy_name     =>   'AUDIT_EMPLOYEES' --VARCHAR2   IN
        );

    EXCEPTION
        WHEN OTHERS THEN
            SYS.DBMS_OUTPUT.PUT_LINE(
                                        'Auditoria AUDIT_EMPLOYEES  no existe!'
                                    );
END;
/

BEGIN
    SYS.DBMS_FGA.ADD_POLICY(
         --Argument Name        Value                           Type      In/Out
         ---------------------- -----------------------       ------
         object_schema     =>   'HR'                          --VARCHAR2  IN
         ,object_name      =>   'EMPLOYEES'                   --VARCHAR2  IN
         ,policy_name      =>   'AUDIT_EMPLOYEES'             --VARCHAR2  IN
         ,audit_condition  =>   'EMPLOYEE_ID IS NOT NULL'     --VARCHAR2  IN
         ,audit_column     =>   'EMPLOYEE_ID'                 --VARCHAR2  IN
         ,handler_schema   =>   'HR'                          --VARCHAR2  IN
         ,handler_module   =>   'PRC_AUDIT_EMPLOYEES'         --VARCHAR2  IN
         ,enable           =>   TRUE                          --VARCHAR2  IN
         ,statement_types  =>   'SELECT,INSERT,UPDATE,DELETE' --VARCHAR2  IN
        );

    SYS.DBMS_OUTPUT.PUT_LINE(
                                'Auditoria AUDIT_EMPLOYEES creada con éxito.'
                            );

    EXCEPTION
        WHEN OTHERS THEN
            SYS.DBMS_OUTPUT.PUT_LINE(
                        'Error creando auditoria AUDIT_EMPLOYEES. Detalle: '
						||SQLERRM
                    );
END;
/

Tener presente que los anteriores Scripts fueron ejecutados con el usuario administrador SYSTEM. Ahora conectado desde con el usuario HR ejecutamos la siguiente consulta, notar el uso de la variable de entorno :emp para que se nos pida el valor a consultar:














Consultamos la tabla hr.consultas_tab_employees conectados con el usuario SYSTEM.








Nuevamente con HR insertados un registro en la tabla hr.employees:

Reconsultamos la tabla hr.consultas_tab_employees conectados con el usuario SYSTEM.








Como ultima prueba nos conectamos con HR mediante SQL PLUS y realizamos una consulta del nuevo empleado:














De igual forma verificamos con SYSTEM la anterior consulta en la tabla hr.consultas_tab_employees. Notar como en el campo programa aparece SQL*Plus.







Para nuestras pruebas creamos una tabla donde almacenamos las informaciones que entendemos importantes, de igual forma Oracle guarda un registro por cada auditoria realiza en la tabla sys.dba_fga_audit_trail, puede también hacer uso de ella:






Espero este contenido les haya sido de utilidad, si tienen preguntas o dudas no duden en dejárnoslas saber.



domingo, 27 de abril de 2025

Manejando las Transacciones Bloqueadas

Objetivos:

 Describir las Secciones de Oracle.
 Consultar las secciones activas.
 Conocer los metodos para terminar y/o desconectar las sesiones activas.
 Ver y terminar los bloqueos de Transacciones.






_______________________________________________________________________
Las Sesiones de Oracle.

Una sesión no es más que la conexión entre una aplicación X y la Base de Datos Oracle con sus respectivos objetos.

Puede consultar y obtener información de las sesiones de Oracle mediante las vistas V$SESSION GV$SESSION. Estas vistas contienen entre otros, los campos sid, serial#, inst_id útiles para dropear las secciones.

SELECT
        vs.sid
        , vs.serial#
        , vs.*
FROM    sys.v$session vs
;

SELECT
        gvs.sid
        , gvs.serial#
        , gvs.inst_id
        , gvs.*
FROM    sys.gv$session gvs
;

_______________________________________________________________________
Los Bloqueos de Oracle.

Oracle ofrece varias vistas que permiten consultar los bloqueos de transacciones sobre los distintos objetos de base de datos. Una de ellas es la vista V$LOCK, esta muestras los bloqueos activos en la base de datos sin muchos detalles del objeto bloqueado.

A continuación un ejemplo de la utilidad de la vista V$LOCK:

    1. Conectado con HR ejecutamos la consulta:
SELECT
        employee_id
        , first_name
        , last_name
        , email
FROM    hr.employees
WHERE   employee_id =   100
;








    2. Actualizamos el campo email, no ejecutamos COMMIT alguno y re ejecutamos la anterior consulta:
UPDATE  hr.employees
    SET email   =   email||'@company.com'
WHERE   employee_id =   100
;






    3. Conectado con un segundo usuario (SYSTEM en mi caso) ejecutamos los mismos script anteriores:





















/*Debido a que el usuario HR no ejecutó COMMIT luego del UPDATE, esa transacción está pendiente y ningun otro usuario puede ver los cambios.*/

    4. Con el usuario SYSTEM tratamos de actualizar el mismo campo email para el empleado 100 y notamos como la transacción no se completa debido al bloqueo del registro:














    5. Ahora conectado con un tercel usuario (SYS en mi caso) ejecutamos la siguiente consulta:

SELECT
        (
            SELECT  s.username
            FROM    sys.v$session s
            WHERE   s.sid=bker.sid
        )           AS  usuario_bloqueador,
        bker.SID    AS  sid_bloqueador,
        (
            SELECT  s.username
            FROM    sys.v$session s
            WHERE   s.sid=bked.sid
        )           AS  usuario_bloqueado,
        bked.SID    AS  sid_bloqueado
FROM
        sys.v$lock bker
        JOIN    sys.v$lock bked
            ON  (
                bker.id1 = bked.id1
                AND     bker.id2 = bked.id2
                )
WHERE
        bker.block = 1
AND     bked.request > 0
;





_______________________________________________________________________
La Vista V$LOCKED_OBJECT
La vista V$LOCKED_OBJECT permite ver las transacciones bloqueadas en la Base de Datos con más detalle, permitiendo conocer el objeto bloqueado.

La siguiente consulta muestra las mismas sesiones bloqueadas con el objeto que contiene el bloqueo:

SELECT
        o.owner||'.'||o.object_name     AS  objeto
        ,o.object_type                  AS  tipo_bojeto
        ,s.username                     AS  usuario_conexion
        ,s.sid
        ,s.serial#
        ,s.status
        , DECODE(s.status, 'INACTIVE', 'BLOQUEADOR', 'ACTIVE', 'BLOQUEDADO', 'DESCONOCIDO') AS  DESR_USUARIO
FROM
        sys.gv$locked_object bo
        JOIN    sys.gv$session s
            ON  ( s.sid = bo.session_id)
        JOIN    sys.dba_objects o
            ON  (bo.object_id    =   o.object_id
                    AND bo.inst_id      =   s.inst_id)
;






_______________________________________________________________________
Eliminando Bloqueos de Base Datos
Oracle ofrece varios métodos para desbloquear una transacción. Puede utilizar las sentencias:

    ALTER SYSTEM KILL SESSION 'SID, SERIAL#' [IMMEDIATE];

La anterior sentencia revierte las transacciones en curso, libera los bloqueos y recupera parcialmente los recursos utilizados; si no incluimos la clausula IMMEDIATE la sesión es marcada como 'marked for kill' para que ésta se elimine tan pronto como le sea posible, teniendo en cuenta que dicho proceso puede tomar varios minutos en completarse. 

    ALTER SYSTEM DISCONNECT SESSION 'SID, SERIAL#' [POST_TRANSACTION IMMEDIATE];

La pasada sentencia es un método alternativo para eliminar transacciones bloqueadas. Mientras que KILL SESSION solicita a la sesión que se auto elimine automáticamente, DISCONNECT SESSION termina el proceso del servidor dedicado. Lo que es igual a terminar el proceso desde el sistema operativo.

La cláusula POST_TRANSACTION espera a que se completen las transacciones en curso para luego desconectar la sesión, la cláusula IMMEDIATE desconecta la sesión y las transacciones en curso se revierten inmediatamente.

Tener pendiente que en la sintaxis [ ]  indica que ambas cláusulas son opcionales, pero esto no es así, se deben especificar una o ambas, de lo contrario recibiría un error. Si ambas cláusulas son incluidas IMMEDIATE seria ignorada.

ALTER SYSTEM KILL SESSION '1473, 24750' IMMEDIATE;

ALTER SYSTEM DISCONNECT SESSION '1473, 24750' IMMEDIATE;
/*Las dos sentencias anteriores muestran un ejemplo de como terminar la sesión bloqueadora.*/


DECLARE

    CURSOR  cur_sessions    IS
        SELECT
                vs.sid
                , vs.serial#
        FROM    sys.v$session vs
        WHERE   sid <>   SYS_CONTEXT('USERENV', 'SID')
        ;

BEGIN

    FOR i   IN  cur_sessions    LOOP
    BEGIN
        EXECUTE IMMEDIATE 'ALTER SYSTEM KILL SESSION '''||i.sid||', '||i.serial#||''' IMMEDIATE';

    EXCEPTION
    WHEN OTHERS THEN
        BEGIN
            EXECUTE IMMEDIATE 'ALTER SYSTEM DISCONNECT SESSION '''||i.sid||', '||i.serial#||''' IMMEDIATE';

        EXCEPTION
            WHEN OTHERSTHEN
                NULL;
        END;
    END;
    END LOOP;

END;
/*El bloque PL/SQL anterior consulta todas las sesiones de base de datos diferentes a la sesión actual y utiliza las sentencias KILL SESSION y DISCONNECT SESSION para eliminarlas o desconectarlas .*/


sábado, 19 de abril de 2025

Función LISTAGG Oracle

 Objetivo:





 Conocer la función LISTAGG.
 Ver algunos ejemplos útiles.
____________________________________________________________

Descripción
La función agregada de Oracle LISTAGG opera sobre una lista de registros y retorna en una sola línea todos los valores separados por un delimitador especificado. En esencia es usada para denormalizar datos de varios registros en un registro único. 
Sintaxis
LISTAGG(measure_expr [, 'delimiter'] ON OVERFLOW ERROR)
  WITHIN GROUP (order_by_clause) [OVER query_partition_clause]

En la Sintaxis:
1. measure_expr es la columna o expresión que se desea concatenar.
Tener en cuenta que los valores NULOS son ignorados.
2. delimiter único es el carácter separador. Este parámetro es opcional, 
3. order_by_clause establece el orden que se mostrará la lista de valores.
4. query_partition_clause devuelve todas las filas y duplica el resultado 
de LISTAGG para cada fila de la partición.
Ejemplos
A continuación algunas consultas que muestran el uso de la función LISTAGG, para ellos usamos las tablas del esquema HR.

SELECT
        e.department_id             AS  departamento
        ,    COUNT(e.first_name)    AS  cantidad_empleados
        , LISTAGG(
                    e.first_name,
                    ', '
                ) WITHIN GROUP( ORDER BY e.first_name)                   AS  empleados_x_dept
FROM    hr.employees    e
GROUP BY e.department_id
ORDER BY cantidad_empleados  DESC;

/*La consulta retorna el listado de todos los empleados agrupados por el departamento al que pertenecen*/
La Cláusula OVERFLOW

La cláusula ON OVERFLOW permite controlar la ocurrencia de la excepción ORA-01489 cuando la cadena retornada supera el limite máximo del tipo de datos retornado. Con esta evitamos el error y en su lugar podemos truncar la cadena retornada.

SELECT
        empleo
        , COUNT(1)  AS  cantidad
        , LISTAGG(detalle_empleado, ';' ON OVERFLOW TRUNCATE '**')
            WITHIN GROUP (ORDER BY empleo)   AS detalle_empleado
FROM
(
SELECT
        j.job_title     AS  empleo,
        '|Código: '          ||e.employee_id||'|'||
        'Nombre: '          ||e.first_name||' '||e.last_name||'|'||
        'Correo: '          ||e.email||'|'||
        'Telefono: '        ||e.phone_number||'|'||
        'Salario: '         ||e.salary||'|'||
        'Departamento: '    ||d.department_name||'|'||
        'Dirección: '       ||l.street_address||', '||l.city||', '||
        l.state_province||', '||l.postal_code||', '||c.country_name
        AS  detalle_empleado
FROM
        hr.employees e
        LEFT    JOIN    hr.departments d
            ON  (d.department_id    =   e.department_id)
        LEFT    JOIN    hr.jobs j
            ON  (j.job_id    =   e.job_id)
        LEFT    JOIN    hr.locations l
            ON  (l.location_id    =   d.location_id)
        LEFT    JOIN    hr.countries c
            ON  (c.country_id   =   l.country_id)
)
GROUP  BY   empleo
ORDER BY    cantidad DESC
;
/*En la anterior consulta unimos distintas tablas para traer las informaciones relativas a los empleados; Notar el uso de la cláusula ON OVERFLOW TRUNCATE '**'; de omitirla se generaría la mencionada excepcion ORA-01489*/


viernes, 18 de abril de 2025

Instalación del Esquema HR en Oracle 19C

 Objetivo:




 Instalar el esquema HR de forma manual en la versión 19C de la Base de Datos Oracle.
____________________________________________________________

Introducción
La versión 19C de la Base de Datos Oracle no instala por defecto el esquema HR y sus respectivos objetos, por suerte existe una forma muy fácil de instalarla y aquí te la mostramos.


Esquema HR
Este esquema resulta ser una herramienta util para aprender y practicar las distintas sentencias SQL y PL/SQL. Este contiene tablas, vistas, triggers, constrains etc.

La siguiente imagen muestra la estructura de sus tablas:

Instalación Esquema HR
Abrimos el Command Prompt de Windows, escribimos sqlplus y presionamos la tecla Enter y nos conectamos con SYSTEM:


Luego ejecutamos el Script Esquema_HR.sql, el cual puede ser descargado mediante este LINK de Google Drive:


Yo instalé el script via SQL PLUS pero ustedes puedes ejecutarlo con la herramienta que entiendan, de igual forma si tienen preguntas o dudas pueden dejarme saber por la via que entiendan,