lunes, 9 de mayo de 2011

Concurrents Hello World !!!!!

Hace algún tiempo cuando comenzaba a desarrollar para la EBS me pidieron crear un concurrente ("Con que?" fue mi pregunta). por lo que hoy decidí hacer un pequeño manual con el "hola mundo" en los concurrentes.

Así que primero un poco de teoría:

Concurrente: Es el medio que tienen los usuarios para ejecutar procesos en el servidor, sin tener acceso al usuario APPS ( Pon ningun motivo un usuario debe tener acceso a esta cuenta, incluso ni siquiera los desarrolladores deberiamos tener acceso a este usuario). La mayoría de las ejecuciones de concurrente se realizan por medio del menu:
ver->solicitudes->ejecutar nueva solicitud->solicitud unica




Si seleccionan en el recuadro amarillo, nos mostrara la lista de programas a los que tenemos acceso.

Ahora que ya se como ejecutarlo como rayos se crean estas cosas.

5 Pasos:

1.- Se genera un ejecutable, esto quiere decir cualquier cosa que se va a procesar en el servidor , la EBS soporta ejecutables pro C, java, perl, pl/sql,reports, etc. (el ejemplo que les daré esta en pl/sql).
ejemplo:
CREATE OR REPLACE PROCEDURE APPS.XXX_TST (errbuf OUT VARCHAR2
 /*Mensaje que le regresa el procedimiento al adminstrador de concurrente, este mensaje se muestra en el administrador de concurrente*/ , retcode OUT NUMBER/*Codigo de error que el concurrente regresa al administrador de concurrente sobre el estatus de del concurrente: retcode :=0; El concurrente finaliza normal sin color retcode :=1; El concurrente finaliza en ADVERTENCIA color Amarillo retcode :=2; El concurrente finaliza en ERROR color rojo */,oper1 varchar2 ,oper2 NUMBER )
IS BEGIN
/* apps.fnd_file.output & apps.fnd_file.log constantes que represntan sobre que archivo se realizaran las operaciones del paquete fnd_file. apps.fnd_file.put(which,buff); este comando escribe en el archivo seleccionado los datos que se coloquen en el segundo parametro de entrada. apps.fnd_file.new_line(which,lines);este comando escribe en el archivo seleccionado tantos saltos de linea como se indique en el segundo parametro apps.fnd_file.put_line(which,buff);este comando escribe en el archivo seleccionado los datos que se coloquen en el segundo parametro de entrada concatenados con un salto de linea. */
apps.fnd_file.put(apps.fnd_file.output,'Linea 1 Hola Mundo');
apps.fnd_file.new_line(apps.fnd_file.output, 2);
apps.fnd_file.put(apps.fnd_file.output,'Linea 3 Hola Mundo');
apps.fnd_file.put(apps.fnd_file.output,'-Linea 3 Hola Mundo parte 2');
apps.fnd_file.new_line(apps.fnd_file.output, 1);
apps.fnd_file.put_line(apps.fnd_file.output, 'Linea 4 Hola Mundo');
apps.fnd_file.put(apps.fnd_file.output,'Linea 5 Hola Mundo');
apps.fnd_file.put(apps.fnd_file.log,'Linea LOG 1 Hola Mundo');
apps.fnd_file.new_line(apps.fnd_file.log, 2);
apps.fnd_file.put(apps.fnd_file.log,'Linea LOG 3 Hola Mundo');
apps.fnd_file.put(apps.fnd_file.log,'-Linea LOG 3 Hola Mundo parte 2');
apps.fnd_file.new_line(apps.fnd_file.log, 1);
apps.fnd_file.put_line(apps.fnd_file.log, 'Linea LOG 4 Hola Mundo');
apps.fnd_file.put(apps.fnd_file.log,'Linea LOG 5 Hola Mundo'); errbuf:='HAY ALERTAS';
retcode :=1;
errbuf:='HAY ERRORES';
retcode :=2;
errbuf:='NO HAY ERRORES';
retcode :=0;
END;


2.- Se define el ejecutable, desde la responsabilidad Desarrollador de aplicaciones(Application Developer)/Administrador de Sistema(System Administrator) en el menu:Concurrente->Programa->Ejecutable(Concurrent->Program->Executable) se capturan los datos de tu ejecutable. se podría decir que esta pantalla es solo una definición global del ejecutable.

3.- Se define el programa desde la responsabilidad Desarrollador de aplicaciones(Application Developer)/Administrador de Sistema(System Administrator) en el menu:Concurrente->Programa>Definir->(Concurrent->Program->Define) , aquí se capturan los datos que le servirán al usuario para ejecutar su programa, como son : cual es el ejecutable que utilizara?, con que parámetros?, que parámetro es obligatorio? este programa es incompatible con otro? que tipo de salida da este programa?, etc. aqui les dejo un ejemplo de la definición de  programa.


4.- Se define quien va a ejecutar este programa,  en la ebs el primer nivel donde se define que puede hacer un usuario es la responsabilidad que este tiene, a esa responsabilidad se le agregan todas las funcionalidades que el usuario debería ser capaz de realizar, ejemplo:



  
5.- Como se puede observar la responsabilidad tiene asociado un grupo de solicitudes, el grupo de solicitudes es básicamente la lista de programas que el usuario que tiene esa responsabilidad puede ejecutar.

Listo !!!! una vez que ya lograron este paso, ya pueden ejecutar el programa que ustedes realizaron.

Ahora lo ejecutamos y que sucede, dependiendo de la forma en que hayan codificado los códigos de error, el proceso puede finalizar:
a) 2300206  retcode:=0;   ejemplo de proceso normal.
b) 2300210  retcode:=1;  ejemplo  de proceso con advertencias.
c) 2300206  retcode:=2;  ejemplo de proceso con error.

Queda del lado del programador el colocar el retcode que le ayude al usuario a identificar mejor la situación en la que se ejecuto el proceso.
Como detalle adicional si como programador no tocas esa variable, el proceso  se marca como finalizado
correctamente cuando termina su ejecución sin lanzar excepciones.

Un proceso de pl/sql, hereda los datos de la sesión con la que se encuentra conectado, que quiere decir esto: Que no se requiere ejecutar ni APPS.FND_GLOBAL.APPS_INITIALIZE.

Con esto queda el ejemplo de como realizar la creación y ejecución de un proceso concurrente escrito en PL/SQL.


En el próximo articulo daré un ejemplo en reports.

martes, 5 de abril de 2011

Updating Twitter from the database, using PL/SQL and OAuth.

Hace poco trate de hacer un ejemplo con de actualizar el estado de twitter desde la base de datos y me encontré con que el api que ocupaba antes ya no funcionaba y el único error que me mandaba es que el método de autentificación básico ya no está siendo soportado. Y yo me dije que tan difícil puede ser el nuevo método . . . Bueno pues difícil no es (Aplausos) , en realidad ahora es más talachudo, porque lo que antes se hacía con un par de llamadas a las funciones nativas de la base de datos, ahora se tiene que hacer  un conjunto de operaciones más complejas, incluso ya hay quienes desarrollaron una opción http://somecodinghero.blogspot.com/2010/09/updating-twitter-from-database-using.html
Y esta funciona, sin embargo me encontré con que no tenía permisos para una de las funciones que mencionan, adicionalmente de que esta opción requería un poco más de investigación, por lo que decidi optar por la otra cara de la moneda y la que siempre nos dice para que te cansas si yo ya lo hice:
“JAVA”

Y como Oracle ya compro java pues dije vamos a darle una oportunidad.
Paso A paso:
1.- Registrar la aplicación: Ir a la siguiente dirección https://dev.twitter.com/

2.- Una vez registrada guardar los datos de nuestra aplicación recién creada, si nos da flojera siéntanse con la libertad de utilizar los datos de la mía, solo recuerden que está diseñada para tipo cliente.

3.- Descargar la última versión estable del api de java http://twitter4j.org/en/index.html
 (Twitter4J is an opensourced software and free of charge.
You can use Twitter4J freely for any commercial and non-commercial projects.) Gratis pues!!,
En el caso de este proyecto se utilizó la versión 2.2.1, pero al ser puramente java, la base aceptara todo sin mayor problema.
Una vez que se ha descargado el api de java hay que desomprimirlo y buscar el siguiente jar:
twitter4j-core-2.2.1.jar
4.-Subir el api a la base de datos:
Este jar se sube a una ruta que pueda leer su servidor de base de datos.
Se ejecuta el siguiente comando en el servidor. “Esta es la parte que realmente es importante”
loadjava twitter4j-core-2.2.1.jar -user user/pwd –f
loadjava es el commando que se utiliza para subir al servidor los archivos de java y convertirlos en objetos de base de datos.
Disponibles para ser publicados a pl/sql o utilizados por otros proyectos de java.
Recordemos que la base de datos de Oracle es muy poderosa, pero que pasa si solo saben lo básico de sql y mucho de java el resultado es sorprendente créanme, porque el Oracle permite sqlj “Obvio” que es una forma de mesclar dentro de los programas de java sentencias de sql como si fuera pl/sql al grado que ya no sabes en que estas programando jejeje.
Hummm hummm bueno regresando al proyecto. Una vez que suban el api, los objetos de esta aparecerán todos inválidos, por lo que queda como labor de nosotros recompilarlos todos , si alguien conoce la sentencia correcta de loadjava para evitar esto por favor postéalo para poder corregir esta parte tan tediosa .
5.-Recompilar el Api, es un poco burdo, pero lo que fue más rápido para mí fue:
SELECT 'alter java class "'||ja.name||'" resolve;'
   FROM ALL_JAVA_CLASSES ja
   WHERE  NAME LIKE 'twit%'
Y el resultado de este query ejecutarlo varias veces hasta reducir el número de objetos inválidos al menor numero posible.
6.-Una vez que el api esta valida en su mayoría (Existen algunos que no pude lograr validar). Podemos comenzar a utilizarla.

El objeto que se creo basándome en los ejemplos que trae consigo el api fue el siguiente:



public final class XXX_JTWEET{
public static String update_status(String argument) 
/* update_status funciona tal cual el ejemplo es hard code, pero ayuda mucho a ver como funciona por lo que la dejo para su uso posterior*/
         public static String get_auth_url(String l_proxy ,String l_proxy_user ,String l_proxy_pass ,String l_proxy_port ,String l_AuthConsumerKey ,String l_ConsumerSecret ,String l_user  ,String l_password )



/* get_auth_url esta función reducida nos regresa la url sobre la que se debe autorizar el acceso de la aplicación a nuestra cuenta de twitter*/

String set_status(String l_proxy
,String l_proxy_user
,String l_proxy_pass
,String l_proxy_port
,String l_AuthConsumerKey
,String l_ConsumerSecret
,String l_token
,String l_token_secret
,String l_access_token
,String l_access_token_secret
,String l_pin
,String l_status
)
}
/* set_status con la información obtenida de la página da autorización publica el estatus en el twitter*/


El proyecto completo y las instrucciones de cómo usarlo se encuentran disponibles en



Ejemplo:


/*enciendan dbms ouput para ver los resultados*/

/*esta parte del codigo unicamente es para cuando registran su programa ante twitter*/

declare

RetVal varchar2(4000);

begin

dbms_output.put_line(XXX_JTWEET_PKG.INITIALIZE (1));

dbms_output.put_line(xxx_jtweet_pkg.get_auth_url(false));

COMMIT;

END;

/



/*una vez que van a la pagina que les regreso el programa anterior deben ingresar el codigo que
       les regreso al programa, este paso se realiza una sola vez
*/

begin

xxx_jtweet_pkg.SET_PIN('2667137');

commit;

end;



/*Así es como deberían enviar los mensajes a twitter desde sus programas */



begin

/*al inicio del programa */

dbms_output.put_line(XXX_JTWEET_PKG.INITIALIZE (1));

/*Cada vez que desean mandar algo*/

dbms_output.put_line(xxx_jtweet_pkg.UPDATE_STATUS('hi from plsql v1.16'));

end;






Cualquier duda que tengan no duden en hacérmela llegar por medio del blog.
         Una vez mas los archivos del proyecto se encuentran disponibles en: http://sourceforge.net/projects/ora-tweet/
 Repasemos rápidamente antes de terminar. lo que se nesecita para poder realizar el uso del api de twitter es:
         Consumer Secret/*Los obtienes al registrar el APP*/
         AuthConsumerKey /*Los obtienes al registrar el APP*/
         Request token /¨*Lo obtienes cuando se genera el auth url*/
         Request token secret  /¨*Lo obtienes cuando se genera el auth url*/
        pin /*Se obtiene al ingresar n la tienda de musical pin a la oauth url*/
        access_token /*Se obtiene al ingresar el pin a la oauth url*/
        access_token_secret  /*Se obtiene al ingresar el pin a la oauth url*/
Ahora si felices Tweets

 

viernes, 1 de abril de 2011

Oracle 11gR2 XE Beta is now available


Para muchas personas esta noticia pasara desapercibida, pero para nosotros los que desarrollamos, muchas veces necesitamos hacer pruebas que no dependan  de qu nuestro dba este haciendo mantenimientos o respaldos o el cliente se este quejando de que tus pruebas alentan su sistema. y es por eso que hoy ya esta disponible la nueva versión de la siempre confiable XE ,
Disponible para su descarga aqui Oracle XE 11G 
En el portal de Oracle.

Que lo disfruten!!!

Project Status Inquiry (PSI) Consulta de estado de Proyecto.

Proyectos : es el modulo encargado del manejo de costos, ingresos, recursos , tareas, etc  de un proyecto.

Brinda información detallada sobre el estado del mismo por medio de una pantalla muy practica donde te permite dar información de una manera tan flexible que asusta, y digo asusta por que con los conocimientos adecuados de la estructura del modulo de Proyectos y conocimientos de el lenguaje PL/SQL le pueden ahorrar tanto trabajo al usuario de una manera casi ilimitada. La pantalla de la que hablo maravillas es una pantalla que en algún momento mi amigo Jose de Jesús Martinez Cañas, tuvo a bien explicarme el funcionamiento de la pantalla PSI.

El PSI tiene una peculiaridad que  pocas pantallas de la aplicación tienen, y esto es : Es una pantalla que pueden modificarse la forma en la que se entregan los  datos de prácticamente todas las columnas, esto quiere decir, que si uno desea puede reconstruir todos los datos que te presenta la pantalla, las etiquetas, promedios, sumatorias, minería de datos a otros módulos que tengan que ver con el proyecto o hasta lo que no tenga que ver con el proyecto se puede pintar en esta pantalla.

Las pantallas de configuración de esta pantalla nos dejan muy claro a los desarrolladores que la persona que hizo esta pantalla seguramente le cambiaron la definición de lo que querían que se viera en esta pantalla , que el decidió dejarle a los funcionales la tarea de definir que pintara la pantalla con la información disponible del modulo.

ejemplo:
Flexibilidad en cada columna.

La etiquetas del reporte también son edita bles desde esta pantalla 

Son 33 columnas para el nivel Proyecto

Y esto se puede configurar tanto para el nivel proyecto como para tarea y Recursos.
 Ahora como es tan mágico esta pantalla, como permite tal cosa, acaso las pantallas del psi se construyen en tiempo de ejecución?

No es magia ni algo remotamente parecido, lo que sucede es que genera vistas en la base de datos cuando uno le da generar visualización, vistas que como su nombre lo dicen son genéricas.

PA_STATUS_PROJ_GENERIC_V

PA_STATUS_TASK_GENERIC_V

PA_STATUS_RSRC_GENERIC_V

Estas 3 vistas contienen permiten extraer los datos como los solicito el usuario en la configuración en cada uno de los niveles del reporte, sin embargo cuando uno trata de ejecutarlas en la base de datos estas no regresan nada. como inicializar las vistas del PSI para que nos regresen valores es el  reto.

Para que no se quiebren la cabeza recordemos como funciona la aplicación.

La seguridad desde R11 y ahora en r12 se maneja por medio de los perfiles de las responsabilidades y para poder emular lo que hacen las pantallas de la aplicación para restringir el acceso a los usuarios se tienen que ejecutar siempre las funciones que inicializan los valores de la responsabilidad del usuario, y a partir de la R12 se implemento la seguridad por medio de los perfiles por lo que ahora se agregan las funciones MO.
BEGIN
 FND_GLOBAL.APPS_INITIALIZE(1117,50719,275);
/*FND_GLOBAL.APPS_INITIALIZE(user_id,resp_id,resp_appl_id);*/
MO_GLOBAL.init('PA');
 /*MO_GLOBAL.init(application short name);*/
pa_budget_utils.set_entry_level_code('A');
pa_security.SET_VALUE('ALLOW_QUERY','Y');

APPS.PA_STATUS.pa_status_driver(38,NULL
,NULL,NULL,'AC','AR'
,TRUNC(SYSDATE,'MM'),LAST_DAY(SYSDATE),1);
/*PROCEDURE pa_status_driver (
  x_project_id =>Id Proyecto  
  , x_task_id => Id tarea
  , x_resource_list_id => Id lista de recursos
  , x_resource_list_member_id =>  id miembro
  , x_cost_budget_code  =>codigo del tipo de presuspuesto de costos
  , x_rev_budget_code IN => codigo del tipo de presupuesto de Ingresos
  , x_start_date IN DATE =>Fecha inicial de periodo  a analizar
  , x_end_date IN DATE =>Fecha final de periodo  a finalizar
  , x_factor IN NUMBER=>Factor entre el que se dividirán las operaciones
);
*/ 

END;
 /

 Este procedimiento anónimo estaría inicializando las variables de ambiente suficientes para que te permita realizar consultas sobre las vistas estándar del proyecto y podemos realizar toda la minería de datos que queramos.

Espero les sea útil.

jueves, 31 de marzo de 2011

ORA-01403: no data found,ORA-01403: no data found ,ORA-23494: too many rows and Select Into

ORA-01403: no data found ,ORA-23494: too many rows for destination and Select Into
ORA-01403: no data found
Cause: In a host language program, all records have been fetched. The return code from the fetch was +4, indicating that all records have been returned from the SQL query.

Action: Terminate processing for the SELECT statement.

ORA-23494: too many rows for destination "string"
Causa: The specified destination has too many rows
Acción: Ensure the specified destination has at most two valid rows before retrying this operation.

Esto es lo que encuentras al buscar este error.

no data found, Como olvidar este error, y aqui te presento a uno de los principales culpables:

Select datos
Into variables
from tabla

Dentro de las mas grandes bendiciones/maldiciones que existen en pl/sql esta esta bendita/maldita sentencia, porque se preguntaran?, bueno pues resulta de que cuando te enseñan esta sentencia, debería venir de la mano con un manual de por que deberías evitar utilizarla, a que me refiero:

Cuando tu utilizas la sentencia select into , significa que de manera directa deseamos obtener información de la base y que nos la deposite dentro de variables en nuestro código, que utilizado correctamente nos puede ahorrar algunas lineas de código dentro de nuestros procedimientos, sin embargo si no estas absoluta y completamente seguros de que tu consulta siempre regresara uno y solo un registro, en caso de que no estés seguro de lo anterior, tu proceso debería estar preparado para lo peor.

es decir deberia por lo menos agregar el siguiente codigo:

begin
Select datos
Into variables
from tabla
exceptions
when no_data_found then
/*lo que quieras hacer cuando no encuentre datos*/
when too_many_rows
/*lo que quieras hacer cuando encuentre mas de un registro */
end;



Espero este pequeño ejemplo sea útil.

miércoles, 30 de marzo de 2011

Order by en columnas de tipo caracter

Normalmente cuando nos encontramos con reportes que entregan una columna de numero de documento , el usuario solicitara que la información se le entregue ordenada con respecto a este campo , pero que pasa cuando esta columna incluye datos tanto alfanuméricos?

a pues si se ordenan puede darte cosas como estas


10000000001
111011
1111
A1201


cual es la solución mas sencilla ,

agregar en las seccion del order by


select (datos)
 from tabla
order by lpad(columna,longitud columna,'0')

 Un ejemplo con la tabla de transacciones de la ebs

select trx_number
  from ra_customer_trx_all
order  by  lpad(trx_number,50,'0')

si esta tabla tuviera solo los datos de arriba los presentaría asi

1111
A1201
111011
10000000001

 Espero que les sea útil , felices reportes.

jueves, 3 de marzo de 2011

ALTER SEQUENCE NEXTVAL ?

Algunas veces cuando realice un proceso que servía para generar la generación de un archivo me solicitaron que le colocara un numero como folio al archivo. Y esto fue muy sencillo solo me base en una secuencia de Oracle. Todo funciono muy bien hasta que llego el momento en el que me dijeron "Necesitamos regenerar la secuencia por que lanzamos muchos archivos mal y no podemos gastar esos folios así por que si".





A pues resulta que no hay una manera directa de colocarle el siguiente valor a una secuencia, y esto se puede conseguir de dos maneras (las que conozco):







  • Drop Sequence: Simplemente hacer drop al objecto de base de datos y colocar en la construción del objeto la sentencia "start with " y el numero en el que les soliciten iniciar:


drop sequence my_seq;



create sequence my_seq



start with 1234



nocache



order;



/





  • Manera comoda, buscando por ahí se encontraran con que no existe un comando alter sequence nextval, pero hay una manera de hacerlo por medio de jugar con lo que nos brinda Oracle: ALTER SEQUENCE MINVAL, ALTER SEQUENCE INCREMENT BY.


EL siguiente procedimiento de pl se encarga de realizar el truco mas cómodamente :


CREATE OR REPLACE PROCEDURE XXX_RESET_SEQUENCE (

PS_SEQ_NAME IN VARCHAR2, P_STARTVALUE IN NUMBER) AS

LN_VAL NUMBER (30);

MIN_VAL NUMBER (30);

LS_BUFF VARCHAR2(25);

LS_CYCLE_FLAG VARCHAR2(25);

BEGIN

SELECT CYCLE_FLAG

INTO LS_CYCLE_FLAG FROM USER_SEQUENCES

WHERE SEQUENCE_NAME =PS_SEQ_NAME;

EXECUTE IMMEDIATE 'SELECT ' PS_SEQ_NAME '.NEXTVAL FROM dual'INTO LN_VAL;

LN_VAL := -1*(LN_VAL - P_STARTVALUE 1);

EXECUTE IMMEDIATE 'ALTER SEQUENCE ' PS_SEQ_NAME' MINVALUE 0';

LS_BUFF := ' INCREMENT BY ';

EXECUTE IMMEDIATE 'ALTER SEQUENCE ' PS_SEQ_NAME LS_BUFF LN_VAL;

EXECUTE IMMEDIATE 'SELECT ' PS_SEQ_NAME '.NEXTVAL FROM dual'

INTO LN_VAL;

EXECUTE IMMEDIATE 'ALTER SEQUENCE ' PS_SEQ_NAME ' INCREMENT BY 1';

END XXX_RESET_SEQUENCE;

/

Y de la siguiente manera se cambiaria el valor de la secuencia;

BEGIN

XXX_RESET_SEQUENCE('MY_SEQ',2);

END;

/

Ventajas y Desventajas

Drop:

Ventaja puede iniciar desde 0(cero), es directo.

Desventaja, al hacer drop del objeto se invalidan todas las dependencias de este.

Procedimiento:

Desventaja: No me permitió iniciar en 0(cero) el valor más bajo al que llego es 1.

Ventaja: No requiere recompilación de dependencias.

Espero que les sea útil.








lunes, 21 de febrero de 2011

APEX PLUGINS


Navegando por Internet de lo que uno se entera y hoy me toco toparme con los Plug-Ins para APEX, Que es esto?

Pues muchas veces en vez de desarrollar una complicada herramienta para nuestro sistema, debemos darnos la oportunidad de revisar si lo que queremos hacer ya lo hizo alguien mas y es ahí donde entran los plugins que oracle ya a liberado muchas herramientas para que tus aplicaciones sean aun mas completas con un par de clics extra, por ejemplo:

Agregarle el Boton Me gusta de Facebook , cambiar tu estatus en tweeter o agregar la funcionalidad del captcha de google a tu aplicación.

En el siguiente link encontraran una lista de los Plug-Ins que Oracle recomienda, así como los links a el repositorio de Plug-Ins:

Oracle APEX Plug-Ins

Sitio Oficial de Plug-Ins APEX

Espero les sean de utilidad.


domingo, 20 de febrero de 2011

Oracle, Where is the bug ?

Existen ocasiones donde nos encontramos con bugs dentro de nuestros programas y no podemos mostrar la salida de nuestro programa para ir dándonos una idea de donde ocurre el error, para ese tipo de situaciones Oracle nos brinda herramientas como el trace y a este aplicarle el famoso tkprof sin embargo no siempre tenemos a la mano el acceso al servidor por shell o simplemente no tenemos a un dba de cabecera ( yo sigo sin tener el mio y eso que en este proyecto hay 2 ) bueno pues para estas ocaciones lo que yo uso normalmente es un procedimiento que escribe en una tabla y me va dejando una pista te lo que ocurre en mi código.

El script de instalación es el siguiente:

CREATE SEQUENCE XXX_DEBUG_S;

CREATE TABLE "XXX_DEBUG_TAB"

( "ID" NUMBER,

"IDENTIFIER" VARCHAR2(50),

"CHAR_TIME" VARCHAR2(50),

"TEXT" VARCHAR2(4000) );

CREATE OR REPLACE PROCEDURE "XXX_DEBUG_TXT" (pIdentifier In Varchar2, pText In Varchar2) Is pragma autonomous_transaction;

Begin Insert into XXX_debug_tab

(id, identifier, char_time, text)

values

(XXX_DEBUG_S.nextval, pIdentifier, to_char(SYSTIMESTAMP, 'DD/MM/YYYY HH24:MI:SS FF6'), pText);

commit;

End; /


Ahora y esto para que nos sirve, pues es muy sencillo el procedimiento de arriba se encarga de insertar a una tabla cada ves que lo llaman, algo asi:

begin

XXX_DEBUG_TXT('DEPURA','AQUI ESTOY:'||VAR1);

end;


Que tiene esto de practico? Pues que lo puedes meter en cualquier parte de tu código y no altera tu procesamiento natural, ya que al utilizar la sentencia "pragma autonomous_transaction" este procedimiento se ejecuta dentro de una sesión diferente y su commit no afecta tu programa natural permitiendo que tu transacción continúe como si nada hubiese pasado y tu puedes seguir monitoreando desde otra sesión.

Y si ocurre algun error tu puedes ir guardando tus variables o datos que te puedan ayudar a identificar los bugs de tus programas o aquellos programas que te toque revisar.

Espero les sea útil y felices compilaciones ¡¡¡