Cuando empecé a utilizar esta técnica de desarrollo me recuerdo que era bastante tedioso poder crear aplicaciones utilizando AJAX pero gracias a las librerias de PEAR para PHP se nos hace bastante simple el desarrollo.

Poniendolos un poco en contexto, AJAX es una técnica de programación que hace llamadas asíncronas hacia el servidor de aplicaciones, recargándo únicamente el área de la página que deseamos y evitar hacer una recarga total de la página. Bien, PEAR dentro de su gran gama de librerias proporciona un paquete llamado HTML_AJAX que contiene todas las librerias para manejo de AJAX. En este tutorial veremos como hacer uso de estas librerías. Read more…

Cuando un query tarda mucho tiempo a pesar de que la columna sobre la que se filtra tiene un índice es porque estamos pasando por alto algún detalle.

Hace poco en la oficina estábamos haciendo un query sobre una tabla que tenía poco menos que 1 millón de registros, la cuestión es que a pesar de que la columna sobre la que filtrábamos estaba indexada, la consulta seguía tardando aproximadamente 7 segundos, lo cual mataba nuestra aplicación.

El problema fue causado no por ignorancia, ni por deficiencias en el desempeño del servidor, sino más bien por un descuido, ya que el campo por el que filtraba era de tipo texto y el query lo hacíamos así: Read more…

Capitalizar es un anglicismo que proviene del verbo Capitalize, y que en inglés significa pasar a mayúsculas una palabra o pasar a mayúscula la primera letra de una palabra dejando el resto en minúsculas. Y es a esto último lo que se me refiero.

En PostgreSQL existen varias funciones para manejo de strings de uso común, como lower() y upper(), pero no existe una para Capitalizar (gracias a Cristian por la aclaración), por lo que debido a la necesidad, escribí una haciendo uso de las funciones.

  • regexp_replace
  • string_to_array
  • array_dims
  • upper
  • lower

Yo quería hacerlo utilizando backreferences en expresiones regulares, pero no pude aplicar una transformación a la backreference, por lo que si a alguien tiene una mejor forma de hacerlo, espero sus comentario. 😛

Aquí les dejo el código:


CREATE OR REPLACE FUNCTION capitalize(_texto text)
RETURNS text AS
$BODY$
DECLARE
fin INTEGER;
temporal RECORD;
retval TEXT;
BEGIN
retval = ' ';
FOR temporal IN SELECT string_to_array (_texto,' ') AS arreglo LOOP
SELECT regexp_replace(
regexp_replace(
array_dims(temporal.arreglo),'[^1-9]','','g')
,'.','')::integer into fin;
FOR i IN 1..fin LOOP
retval = retval
|| upper(substring(temporal.arreglo[i],1,1))
|| lower(regexp_replace(temporal.arreglo[i],'(.)(.*)','\\2'))
||' ';
END LOOP;
END LOOP;
RETURN trim(retval);
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

Como siempre, espero que les sirva, y Hasta la próxima!

Muy a menudo hacemos queries usando select … where id in (…), por ejemplo:

SELECT id,nombre FROM ejemplo_select_in WHERE edad IN (20,25,50);

Esto es distinto cuando lo queremos hacer en un Store Procedure (SP), y queremos usar un arreglo como parámetro, ya que no usamos la clausula IN, veamos como hacerlo.

Usemos la siguiente tabla para el ejemplo:

id
nombre
edad
1
nombre 1
20
2
nombre 2
20
3
nombre 3
20
7
nombre 7
25
4
nombre 4
50
5
nombre 5
50
6
nombre 6
25

ejemplo:

Si quisieramos obtener los que tengan 20 años haríamos un SP de la siguiente manera: (el ejemplo es trivial pero práctico)

CREATE OR REPLACE FUNCTION sp_get_personas(_edad INTEGER) RETURNS SETOF type_select_in AS
$BODY$
DECLARE
retval record;
BEGIN
FOR retval IN
SELECT * FROM ejemplo_select_in WHERE edad = _edad LOOP
RETURN NEXT retval;
END LOOP ;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

Al ejecutar SELECT * FROM sp_get_personas(25) obtendríamos:

id
nombre
edad
7
nombre 7
25
6
nombre 6
25

Para poder obtener aquellos que tengan 20 y 25 años cambiaríamos el SP y en vez de usar select in usaríamos la función ANY():

CREATE OR REPLACE FUNCTION sp_get_personas(_edad INTEGER[]) RETURNS SETOF type_select_in AS
$BODY$
DECLARE
retval record;
BEGIN
FOR retval IN
SELECT * FROM ejemplo_select_in WHERE edad = ANY(_edad) LOOP
RETURN NEXT retval;
END LOOP ;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

Al ejecutar SELECT * FROM sp_get_personas(25,50) obtendríamos:

id
nombre
edad
7
nombre 7
25
4
nombre 4
50
5
nombre 5
50
6
nombre 6
25

La función ANY(), no es de uso común y en estos casos es la mejor opción.

Les dejo con los Scripts .
Espero que les sirva, Hasta la próxima!.

Una de las preguntas que me hice cuando comenze a utilizar Java como lenguaje de programacion era que la mayoria de las personas a la hora de que necesitaban importar alguna clase especifica de un paquete, estas no se complicaban e importaban todo el paquete, mientras en los IDEs , importaba especificamente la clase que se necesitaba, y si importaban varias clases era una larga lista ya que hacian una linea por cada clase que necesitaban importar. Read more…

Al empezar a utilizar expresiones regulares, una de las primeras situaciones con las que me topé, es la de que algunos de los operadores cuantificadores poseen cierto comportamiento como el de ser perezosos o codiciosos al momento de hacer ‘match’ con la cadena especificada. Antes de explicar de que se trata este comportamiento, recordemos los operadores cuantificadores:

  • *‘ indica que la expresión puede venir cero o más veces,
  • +‘ indica que la expresión puede venir una o más veces,
  • ?‘ indica que la expresión puede o no venir.

Empecemos la explicación con un ejemplo escrito en php y haciendo uso de la librería de expresiones regulares de php: PCRE (Compatibles con Perl).

Supongamos que tenemos analizar un código html en el cual nos interesa extraer el texto que está contenido entre etiquetas ‘div’. El código html de ejemplo es :

<div>esto es un ejemplo de texto</div> <div> se mostrara como funcionan en modo perezoso o codicioso</div>

Para extraer el texto contenido en el div usamos la siguiente expresión regular: <div>(.*)</div>
que utilizando php la definimos así:

$patron = '/<div>(.*)<\/div>/';

Utilizaremos la función preg_match_all para obtener las cadenas que concuerden con la expresión regular propuesta. El script se vería de la siguiente manera:

<?php
$texto = "<div>esto es un ejemplo de texto</div> <div> se mostrara como funcionan en modo perezoso o codicioso</div>";
$patron = '/<div>(.*)<\/div>/U';
preg_match_all ($patron, $texto, $matches);
echo "<pre>";
print_r($matches);
echo "</pre>";
?>


Si ejecutamos el script, podemos ver que la cadena que hace match es:

[0] => 'esto es un ejemplo de texto</div><div> se mostrara como funcionan en modo perezoso o codicioso'.

Pero este resultado no es el que esperabamos. ¿Qué pasó aquí? Es ahora que podemos hablar del cuantificador codicioso, el cual trata de hacer match a la cadena más grande que encuentre. Y eso fue lo que pasó con el script, hizo match desde la apertura de la etiqueta ‘<div>’ y debido al operador (.*) incluyó todo el texto intermedio sin detenerse en el primer cierre ‘</div>’, ya que siguió buscando si encontraba otro cierre de la etiqueta, el cual lo encontró al final de la cadena.

Entonces ¿cómo hacemos para que obtener el texto dentro de cada etiquetas ‘div’? Transformado el cuantificador codicioso en un cuantificador perezoso para que haga match con la cadena más corta que encuentre. Y eso se puede hacer agregando ‘?’ despues de la expresion (.*). La expresión regular quedaría entonces de la siguiente manera:

<div>(.*?)</div>

Reescribiendo el script:

<?php
$texto = "<div>esto es un ejemplo de texto</div> <div> se mostrara como funcionan en modo perezoso o codicioso</div>";
$patron = '/<div>(.*?)<\/div>/';
preg_match_all ($patron, $texto, $matches);
echo "<pre>";
print_r($matches[1]);
echo "</pre>";
?>


Lo ejecutamos y vemos que ahora ya nos devuelve unicamente el contenido que esta dentro de cada etiqueta ‘div’:

Array
(
[0] => esto es un ejemplo de texto
[1] => se mostrara como funcionan en modo perezoso o codicioso
)

Este mismo comportamiento se aplica a los demás cuantificadores:

Codicioso Perezoso
(.*) (.*?)
(.+) (.+?)
(?) (??)

Asi que ahora podemos usarlos de manera codiciosa o perezosa según nos convenga.

Como información adicional, las expresiones regulares PCRE de php nos ofrecen el modificador U (PCRE_UNGREEDY) para poder alterar este comportamiento, haciendo que los cuantificadores que son codiciosos de manera predeterminada, se vuelvan perezosos. Usando este modificador el patrón quedaría así:

$patron = '/<div>(.*)<\/div>/U';

Y eso es todo amigos… hasta la próxima.

 Resulta que ambos comandos, reportan de diferente forma el espacio utilizado en el disco, y para demostrar esto y entenderlo de mejor forma, lo veremos con un ejemplo, acompañados de otro comando amigo el lsof.

Si utilizamos el comando du, de la siguiente forma:


# du -sh /

el -sh significa que queremos el gran total ( s: sumarizar) y que utilice letras para definir los tamaños, MB, GB, etc.

obtenemos el siguiente resultado:

13G /

Luego utilizando el comando df, supuestamente para realizar el mismo cálculo, podriamos utilizar lo siguiente:

df -h /

el -h significa que queremos que utilice letras para definir los tamaños, MB, GB, etc.

para lo que obtendríamos un resultado como este:

Filesystem Size Used Avail Use% Mounted on
/dev/sda3   64G  30G   32G  49% /

y llegamos entonces al punto! segun du tenemos 13G utilizados en nuestro disco y el df nos dice que estamos utilizando 30GB! pregunto entonces donde se encuentran los 17GB que no estan en el disco segun el du? Bueno resulta que el “open file descriptor” es el causante de esta diferencia en resultados, ya que el df toma en cuenta los archivos abiertos y el du realiza sus calculos sobre los archivos almacenados en cada una de las carpetas recursivamente.

 Es ahora donde el “lsof” entra en juego para ayudarnos a saber qué pasa con ese crecimiento en el espacio de disco utilizado. Al ejecutar el comando de la siguiente forma:

lsof -R | more

Obtenemos un resultado como el siguiente:

COMMAND PID PPID USER FD TYPE DEVICE SIZE NODE NAME
init 1 0 root cwd DIR 8,3 4096 2 /
init 1 0 root rtd DIR 8,3 4096 2 /
init 1 0 root txt REG 8,3 32652 7028751 /sbin/init
init 1 0 root mem REG 0,0 0 [heap] (stat: No such file or directory)
init 1 0 root mem REG 8,3 9592 7260587 /lib/tls/i686/cmov/libdl-2.3.6.so
init 1 0 root mem REG 8,3 1241392 7260584 /lib/tls/i686/cmov/libc-2.3.6.so
init 1 0 root mem REG 8,3 79368 7258210 /lib/libselinux.so.1
init 1 0 root mem REG 8,3 219824 7258211 /lib/libsepol.so.1
init 1 0 root mem REG 8,3 88164 7258114 /lib/ld-2.3.6.s

utilicé el “-R” para que me listara el proceso padre y así identificar quien está utilizando dichos archivos. Con ello podemos llegar de una mejor forma a detectar ese crecimiento “fantasma”.

Como ejemplo practico podriamos hacer lo siguiente.

Primero utilicemos los siguientes comandos para el /home:

# df -h /home

# du -s -h /tmp

ahora creamos un archvo GRANDE:

# cd /home/user
# cat /bin/* >> demo.txt
# cat /sbin/* >> demo.txt

Ingresamos a otra consola y abrimos el archivo demo.txt utilizando el editor de texto vi :

# vi /home/user/demo.txt

sin cerrar vi (mantengalo corriendo en esa consola), regrese a la primer consola y borre el archivo demo.txt

# rm demo.txt

Ahora corra du y df y observará la diferencia.

# df -h /home
# du -s -h /tmp

Regrese a la siguiente consola y cierre vi sin grabar el archivo y la aparente causa principal del problema pareciera haberse resuelto, y la salida de los comandos du y df podria ya estar correcta. Este ejemplo fue solamente para “replicar” estas circunstancias en un entorno de pruebas ya que en el entorno de producción, estas diferencias se van dando por medio de los servicios que se estén ejecutando, por ello incluí el “lsof” ya que puede ayudarnos a detectar al culpable de un crecimiento en disco que pudiera llegar a “saturarlo”.

Bueno, este fué mi primer post a tipsdeaweb.com, espero volver pronto con alguno de esos tips que nos gustaría encontrar facilmente y que lo mas probable es que no esten en español.