jueves, marzo 15, 2007

Netbeans 5.5 VWP con MyFaces Tomahawk

Bueno este es la primera cosa que coloco sobre Java, aunque colocare mas, esto lo hago porque era algo demasido sencillo y que no pude resolverlo rapido, si hay otro despistado como yo que no sepa como hacerlo pos espero que lo siguiente le ayude.

Para poder trabajar con Netbeans y MyFaces encontre la siguiente GUIA, solo agregare algunas pasos para trabajar con el paquete VWP .

1. En mi caso solo necesito trabajar con la extension de los componentes de JSF, solo manipulare el componente del menu JSCookMenu ,tampoco necesito todas las librerias de MyFaces, asi que solo se incluira en el proyecto las siguientes librerias:
* Tomahawk (tomahawk-1.1.3.jar)
* commons-el-1.0.jar
* commons-lang-2.1.jar
2. Luego de incluir las librerias, debemos de agregar lo siguiente en modo de edicion JSP
xmlns:t="http://myfaces.apache.org/tomahawk"

3. Ahora agregamos el codigo que se encuentra en la guia de netbeans con myfaces y configuran el filter que indican en la guia en el web.xml.

Si todo ha salido bien, a la hora de correr el proyecto tendran la siguiente salida:
Una ultima cosa, no se podra ver en modo de diseño los componentes de myfaces en VWP, ese es el unico pero, aunque puedo vivir con eso.

lunes, enero 29, 2007

Tablas temporales en PostgreSQL

Bueno la creacion de tablas temporales a partir de un sql es muy facil, la sentencia seria la siguiente:
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name
[ (column_name [, ...] ) ] [ [ WITH | WITHOUT ] OIDS ]
AS query
si se realiza una tabla temporal para una operacion compleja y esta falla estando en una transaccion la tabla temporal se detruye pero si no hay ningun problema entonces la vida de esta estara hasta que la sesion haya terminado.
Un pequeño ejemplo:

=#BEGIN;
=#CREATE TEMP TABLE prueba AS SELECT * FROM CIUDAD;
=#SELECT * FROM prueba;
ciud_id | ciud_codigo | ciud_nombre
----------+---------------+-------------
1 | 123 | Bogota
2 | 456 | Medellin
3 | 5 | ñoño
4 | 789 | Cali
(4 filas)
=#ROLLBACK;
ROLLBACK
=# SELECT * FROM prueba;
ERROR: relation "prueba" does not exist
si no realizaramos un rollback sino un commit entonces la tabla no se destruiria,
seguiria hasta que se termine la sesion con la base de datos.

Aqui es donde nace la pregunta: Que pasaria si se utiliza un pool de conexiones como pgpool?? ademas creo que en la documentacion del proyecto nombraban el inconveniente, pero bueno buscando un poco en el manual, en la referencia del comando create table indican algo sobre tablas temporales:
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name ( [
{ column_name data_type [ DEFAULT default_expr ] [ column_constraint [ ... ] ]
| table_constraint
| LIKE parent_table [ { INCLUDING | EXCLUDING } DEFAULTS ] }
[, ... ]
] )
[ INHERITS ( parent_table [, ... ] ) ]
[ WITH OIDS | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace ]

y leyendo un poco la parte de ON COMMIT:

ON COMMIT
The behavior of temporary tables at the end of a transaction block can be controlled using ON COMMIT.
The three options are:

PRESERVE ROWS
No special action is taken at the ends of transactions. This is the default behavior.
DELETE ROWS
All rows in the temporary table will be deleted at the end of each transaction block.
Essentially, an automatic TRUNCATE is done at each commit.
DROP
The temporary table will be dropped at the end of the current transaction block.
Entonces comence a probar a crear una tabla temporal indicando ON COMMIT DROP el cual me interesa probar:

=# CREATE TEMP TABLE prueba AS select * from ciudad ON COMMIT DROP;
ERROR: syntax error at or near "on" en el carácter 50
LINEA 1: create temp table prueba as select * from ciudad on commit d...

Hum... no funciona.. busque en la lista de ayuda en ingles y ya alguien habia tenido la misma inquietud donde la respuesta fue la siguiente:

> But how can I create a table using a query and putting ON COMMIT DROP.

You can''t. Use INSERT ... SELECT to fill the table, instead.

Entonces hay que crear la tabla primero y luego llenar la tabla con una consulta, la prueba:

=# BEGIN;
BEGIN
=# CREATE TEMP TABLE prueba(ciud_id integer, ciud_codigo numeric, ciud_nombre varchar) ON COMMIT DROP;
CREATE TABLE
En el sql de la creacion de la tabla temporal solo me funciono indicando el nombre y tipo del campo.

=# \d prueba
Tabla «pg_temp_1.prueba»
Columna | Tipo | Modificadores
-----------------+---------------------+-----------------
ciud_id | integer |
ciud_codigo | numeric |
ciud_nombre | character varying |

=# INSERT INTO prueba SELECT * FROM ciudad;
INSERT 0 4
=# SELECT * FROM prueba;
ciud_id | ciud_codigo | ciud_nombre
----------+---------------+-------------
1 | 123 | Bogota
2 | 456 | Medellin
3 | 5 | ñoño
4 | 789 | Cali
(4 filas)

=# COMMIT;
COMMIT
=# SELECT * FROM prueba;
ERROR: relation "prueba" does not exist
De esa forma conseguia el comportamiento que queria, que cuando la transaccion se confirme la tabla se destruya sin necesidad de terminar la sesion con la base de datos, una ultima cosa esto lo probe en la version 8.1.4.

miércoles, enero 10, 2007

EL CTID

Los CTID son usados para identificar registros físicos específicos con valores de bloque y de desplazamiento (offset). Los CTID cambian después de que los registros son modificados y recargados. Son usados por entradas indexadas para apuntar a registros físicos.

Bueno en mi ultima entrada indique como eliminar registros repetidos, en ese ejemplo se indico un como con DISTINCT, el dia de hoy me encuentro con un mensaje de correo en la lista de ayuda de PostgreSQL en español de Alvaro Herrera donde indica como realizar la misma operacion utilizando el ctid y tambien dejando una reflexion, a continuación indico el contenido del correo:


> create or replace function eliminar_ubiprograma_repetidos()
> as
> $body$
> declare
> var_dir numeric;
> var_prg numeric;
> cur_ubiprg refcursor;
> begin
> OPEN cur_ubiprg for select dir_codigo,prg_codigo,count(*) from
> ubicacion_programa group by dir_codigo,prg_codigo having count(*)>1
> LOOP
> fetch cur_ubiprg into var_dir,var_prg;
> select ctid from ubicacion_programa where prg_codigo=var_dir and
> dir_codigo=var_prg

No no no no no. Debes dejar de pensar en modo procedural. Debes dejar
de programar diciendole a la maquina paso por paso que es lo que debe
hacer. Debes encontrar la manera de decirle a la maquina _QUE_ es lo
que debe hacer, no _COMO_ hacerlo. Si no consigues pensar de esa manera
jamas lograras entender como hacer funcionar una base de datos.

Aca en tu funcion lo que estas haciendo es decir "por favor traigame
todos los CTIDs que cumplan tal condicion", y a continuacion pedir para
cada CTID conseguir que se haga tal o cual cosa. Eso es perdida de
tiempo y recursos y escribir mil lineas que estan de sobra.

Mira, aca un ejemplo de como se hace realmente:

alvherre=# create table duplos (a int );
CREATE TABLE
alvherre=# insert into duplos values (1);
INSERT 0 1
alvherre=# insert into duplos values (1);
INSERT 0 1
alvherre=# insert into duplos values (2);
INSERT 0 1
alvherre=# insert into duplos values (2);
INSERT 0 1
alvherre=# insert into duplos values (2);
INSERT 0 1
alvherre=# insert into duplos values (3);
INSERT 0 1
alvherre=# select * from duplos;
a
---
1
1
2
2
2
3
(6 rows)

Ok, hay duplicados. Como se eliminan? Observa esto:

alvherre=# select ctid, a from duplos;
ctid | a
-------+---
(0,1) | 1
(0,2) | 1
(0,3) | 2
(0,4) | 2
(0,5) | 2
(0,6) | 3
(6 rows)

Queremos dejar (0,1) pero eliminar (0,2); dejar (0,3) pero eliminar (0,4) y
(0,5); y dejar (0,6). Como se expresa esto? Observa:

alvherre=# select min(ctid), a from duplos group by a;
min | a
-------+---
(0,6) | 3
(0,3) | 2
(0,1) | 1
(3 rows)

Wow, aca tenemos justo los que queremos dejar! Ahora como se borra el resto?

alvherre=# delete from duplos where ctid not in (select min(ctid) from duplos group by a);
DELETE 3
alvherre=# select * from duplos;
a
---
1
2
3
(3 rows)


Listo. Nada de jugarretas con cursores ni loops.

Puedes perder todo el tiempo que quieras tonteando con shared_buffers y
discos en RAID y servidores gigantescos, pero si cuando te vas para tu
casa has dejado un loop en PL/pgSQL que podia haberse escrito como una
simple consulta, el rendimiento de tu servidor sera malo y la culpa sera
tuya.

Si _realmente_ quieres aprender a programar y dejar de tontear con Java
o Visual Basic, que son juguetes para niños, aprende LISP o Scheme y
veras como el mundo cambia de color de una forma que te sorprendera.

--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.