miércoles, 31 de octubre de 2007

Frases celebres

I wrote when I didn't know the life. Now that I understand what it means. The life can't be written, just can lived.

Oscar Wilde

El que no posee el don de maravillarse ni de entusiasmarse, más le valdría estar muerto, porque sus ojos están cerrados".

Albert Einsten


Si de nada sirve vivir, busca algo porque morir.

Fito Paez


Un pesimista es un optimista bien informado.

Jean Paul Sartre


Nunca hay viento favorable para el que no sabe hacia dónde va.

Séneca


En nuestros locos intentos renunciamos a lo que somos por lo que esperamos ser.

Shakespeare


Miremos más que somos padres de nuestro porvenir que no hijos de nuestro pasado.-

Miguel de Unamuno


El hombre esta hecho del mismo material con el que se fabrican los sueños.

Shakespeare


No hay venganza como el olvido.

Baltasar Gracián


Vengarse de una ofensa es ponerse al nivel del enemigo: perdonarlo es colocarse sobre él.

Rochefoucauld


Un acto de justicia permite cerrar un capítulo; un acto de venganza escribe un capítulo nuevo.

Marilyn Savant


El principio y el fin son una misma cosa. Los vivos y los muertos forman una sola unidad porque la vida esta permanentemente renovada por la muerte.

M. West

sábado, 20 de octubre de 2007

Habilitar resoluciones mayores a 1024x768 (Intel VGA)

En ubuntu es muy sencillo solo necesitamos instalar el paquete 915resolution con apt de la siguiente forma:


apt-get install 915resolution


Me imagino que en otras versiones de linux debe de funcionar, seria bueno que alguno de ustedes que lo probara nos lo dijera :).

Saludos a todos.


domingo, 14 de octubre de 2007

Corrección del brillo de la pantalla en Linux

Para ajustar el brillo de la pantalla nos valemos de la instruccion xgamma de la siguiente manera: xgamma -gamma 1.0 o cualquiera segun como nos sirva en nuestro monitor.

Aprendamos a comunicarnos por medios electronicos.

No envie archivos adjuntos en formato Microsoft Word, un formato
privativo y secreto, por lo que nosotros no podemos leerlo. Envie el
texto puro, HTML o PDF, entonces todos podrémos leerlo.

Enviar a la gente documentos en formato Word tiene efectos
perniciosos, porque esta práctica los insta a utilizar software de
Microsoft. En efecto, Usted se convierte en un sostén del monopolio de
Microsoft. Este problema específico es un gran obstáculo a la adopción
más amplia de GNU/Linux. ¿Podría, por favor, reconsiderar el uso del
formato Word en la comunicación con otras personas?

miércoles, 12 de septiembre de 2007

Casting al crear indices para campos tipo fecha en Postgresql

La forma de realizar un casting para la creacion de indices en postgresql es mediante cast, un ejemplo de un indice BTREE se muestra a continuacion sobre una tabla con un campo tipo DATE a indexar:

CREATE INDEX idx_fecha_salida ON produccion_large USING BTREE (cast(fecha_salida as date));

Habilitar la cuenta de administrador en Windows Vista Home Premium y Home Basic

La forma de habilitar la cuenta de administrador en windows vista home premium es mediante el comando net user aplicado de la siguiente manera:

1.- Primero damos click en el menu inicio y a continuacion escribimos cmd en el cuadro "inicio / buscar".

2.- En la lista de resultados de busqueda, hacemos click con el boton secundario sobre el simbolo de sistema (cmd) y a continuacion hacemos click en "RUN AS ADMINISTRATOR". Con esto obtenemos un shell con privilegios de administrador.

3.- Ya en el command prompt, escribimos lo siguiente:


NET USER ADMINISTRADOR /ACTIVE:YES


4.- Ya con esto tenemos habilitada nuestra cuenta de administrador y solo bastara fijar su contraseña.


jueves, 16 de agosto de 2007

Tablas y Secuencias Temporales

Hola a todos, hoy se me ocurre escribir sobre tablas y secuencias temporales en postgresql. Las tablas temporales y secuencias temporales son aquellas que solo viven mientras la conexion esta activa y despues son destruidas por el backend de postgresql cuando nos desconectamos. Son similares a las tablas y secuencias normales salvo que son de corta duracion y para crearlas solo basta agregar la palabra temporary a la sintaxis ya conocida, por ejemplo:

CREATE TEMPORARY TABLE clientes AS select * from clientes;

CREATE TEMPORARY SEQUENCE alguna_secuencia START 1;

Saludos.

martes, 14 de agosto de 2007

Obtimizando Select count(*) para tablas con mas de 10 millones de registros en Postgresql

Hola a todos, el dia de hoy me complace escribir sobre la optimización de la consulta select count(*) en postgresql, cuando tenemos tablas muy grandes a veces el problema es el tiempo que se lleva al procesar una consulta lineal del tipo select count(*), obviamente el primer mecanismo seria crear un indice sobre dicha tabla empleando CREATE INDEX. Por ejemplo en una tabla que tengo de nombre produccion tengo al rededor de 11916936 registros, ya son muchos registros :).

A continuación muestro la estructura interna de la tabla produccion:


sicodelico=> \d produccion;
Tabla «public.produccion»
Columna | Tipo | Modificadores
-------------------+---------+---------------------------------------------------------
id | integer | not null default nextval('produccion_id_seq'::regclass)
no_serie | integer | not null default 0
id_modelo | integer | not null
id_personal | integer | not null
fecha_fabricacion | date | not null default '2005-01-01'::date
fecha_salida | date |
Índices:
«produccion_pkey» PRIMARY KEY, btree (id)
Restricciones de llave foránea:
«produccion_id_modelo_fkey» FOREIGN KEY (id_modelo) REFERENCES modelos(id)
«produccion_id_personal_fkey» FOREIGN KEY (id_personal) REFERENCES personal(id)



Pues bien, empezemos creando el indice de la tabla produccion para busquedas mediante numero_serie de la siguiente manera:


CREATE INDEX no_serie_idx ON produccion(no_serie);


Aqui es necesario hacer notar que el crear muchos indices puede traer consecuencias nefastas, ya que cada indice ocupa espacio en disco, y muchos indices pueden ralentizar nuestro sistema por el I/O excedente.

Bueno, bueno, ahora lo que necesitamos hacer es ordenar fisicamente (esto es a nivel de cluster) la información, basandonos en el indice ya creado.

Para hacer esta ordenación nos valemos del comando CLUSTER de postgresql.


CLUSTER no_serie_idx on produccion;


Ya con esto tenemos ordenados nuestros datos con forme a los clusters contiguos del disco duro y con esto evitamos desplazamientos inecesarios de la cabeza lectora del disco duro.

En mi ejemplo tarde 34 segundos para completar el select count(*).

Aqui muestro la salida del Explain Analyze:


sicodelico=> EXPLAIN ANALYZE SELECT count(*) from produccion;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=231018.70..231018.71 rows=1 width=0) (actual time=33775.520..33775.522 rows=1 loops=1)
-> Seq Scan on produccion_large (cost=0.00..201226.36 rows=11916936 width=0) (actual time=0.068..17800.818 rows=11916936 loops=1)
Total runtime: 33775.597 ms


Cuando hice la prueba sin optimizar el disco tardo poco mas de 1 minuto, y sin indice mejor ya ni lo menciono.


Saludos.

sábado, 11 de agosto de 2007

Eliminar restriccion Primary Key en PostgreSQL

Para eliminar la restriccion primary key en postgresql empleariamos la sintaxis siguiente:


ALTER TABLE mitabla DROP CONSTRAINT mitabla_pkey;


En donde mitabla es el nombre de la tabla obviamente y mitabla_pkey es el indice primary key.

Saluditos.

Postgresql y el particionamiento de tablas (Partitioning Tables)

A veces cuando estamos manejando tablas con un numero grande de registros, varios millones o mas es necesario particionar las tablas para obtener un mejor desempeño a la hora de consultar dichas tablas. A este proceso se le suele denominar "Partitioning" y es le metodo usado para descomponer una enorme tabla (father) en un cojunto de tablas hijas (child).

Algunas de las enormes ventajas son:

  • Desempeño mejorado para la obtencion de registros (Querys).

  • Desempeño mejorado para la actualización (update).

  • Indices mas pequeños para cada tabla hija contra indices grandes y dificiles de colocar en memoria en una tabla grande.

  • Eliminación rapida de registros. Empleando DROP TABLE en vez de DELETE.

  • Los datos pueden ser migrados o respaldados en medios economicos y pequeños como DVDs, discos duros extraibles, etc.



En postgresql el tipo de partitioning soportado se denomina particionado mediante herencia de tablas. Cada partición puede ser creada como una tabla hija de una unica tabla padre. La tabla padre normalmente debe de ser una tabla vacia, que representara a todo el conjunto de datos.

Los dos tipos de particionado mas comunes en postgresql son:


  1. Particionar por rangos. La tabla es particionada mediante rangos definidos en base a la columna de llave primary o cualquier columna que no se solape entre los rangos de valores asignados a diferentes tablas hijas.


  2. Particionar por lista. La tabla es particionada listando los valores de cada una de las llaves en cada particion.



En postgresql para poder utilizar dicha técnica es necesario seguir algunos pasos:


  1. Crear la tabla "maestra", de la cual todas las tablas hijas heredaran. Esta tabla no contendra datos, no debe de tener ningun tipo de restricción (check), no debe de tener indice ni nada por el estilo.

  2. Crear todas las tablas hijas heredando de la tabla maestra. Por lo regular estas tablas heredaran todos los campos de la tabla padre y no es necesario crearlos nosotros mismos.

  3. Agregar a todas las tablas hijas las restricciones correspondientes sobre los datos que albergaran. Algunos ejemplos de esto serian: CHECK ( pais IN ('México', 'Argentina')), CHECK ( id_cliente BETWEEN 100 AND 200 ) ... CHECK ( id_cliente BETWEEN 5000 AND 5200), en estos dos ultimos ejemplos para evitar traslapes entre los ids de clientes.

  4. Para cada particion, crear un indice para la columna(s) llave, tambien se pueden poner los indices que a cada quien le convengan. El indice para la llave primaria no es estrictamente necesario, pero en la mayoria de los casos ayuda mucho. Si tu necesitas una llave unica o llave primaria, necesitaras crearla para cada tabla hija.

  5. Definir una regla (RULE) o trigger para redirigir las modificaciones de la tabla padre (master) a la apropiada particion.

  6. Verificar que este habilitado a on el parametro constraint_exlusion (SET constraint_exclusion = on;) en el archivo de configuracion postgresql.conf para que los querys sean optimizados para el partitioning.



Pues bien, procedamos a realizar un ejemplo con esto.

Empecemos creando la tabla maestra para nuestro ejemplo.

El esquema de la tabla quedaria de la siguiente forma:


sicodelico=> \d produccion;
Tabla «public.produccion»
Columna | Tipo | Modificadores
-------------------+---------+---------------
id | integer | not null
no_serie | integer |
id_modelo | integer |
id_personal | integer |
fecha_fabricacion | date |
fecha_salida | date |


Una vez creada la tabla maestra procedemos a crear las tabla hijas que en nuestro ejemplo particionaremos en base al modelo del producto fabricado, que seran 4 tablas hijas en base a los 4 modelos almacenados en nuestra base de datos.

Un leve vistazo de la tabla de modelos nos arroja lo siguiente:


sicodelico=> SELECT * from modelos order by id;
id | modelo | caracteristicas | descripcion | imagen
----+-----------------+------------------------+----------------------+--------
1 | ODIN | 5 litros por minuto | calentador de paso |
2 | DELTA 01 | 7 litros por minuto | calentador de paso |
3 | DELTA 01-PLUS | 9 litros por minuto | calentador de paso |
4 | DELTA 02 | 13 LITROS POR MINUTO | CALENTADOR DE PASO |

(4 filas)


Ahora crearemos las tablas hijas heredando de la tabla "produccion", aqui es donde se crean las restricciones (CHECK) para los datos que albergaran cada tabla hija.


CREATE TABLE produccion_odin ( CHECK (id_modelo = 1) ) INHERITS (produccion);
CREATE TABLE produccion_delta01 ( CHECK (id_modelo = 2) ) INHERITS (produccion);
CREATE TABLE produccion_delta01plus ( CHECK (id_modelo = 3) ) INHERITS (produccion);
CREATE TABLE produccion_delta02 ( CHECK (id_modelo = 4) ) INHERITS (produccion);


Las restricciones CHECK tambien se pueden agregar despues mediante la sintaxis del ALTER TABLE.

Mediante las restricciones impuestas en las tablas aseguramos que no almacenen información que no les corresponde, por ejemplo que en la tabla produccion_odin que contiene registro de todos los calentadores del modelo ODIN no tengan calentadores de otros modelos, como DELTA02.

Ahora necesitamos crear los indices para cada tabla hija creada segun nos convenga para agilizar la busqueda de registros o garantizar la unicidad de los mismos, si necesitamos alguna llave primaria, aqui es donde podemos crearla.

Para el caso de las llaves primarias nos valemos de la sintaxis del ALTER TABLE como por ejemplo: ALTER TABLE produccion_odin ADD PRIMARY KEY (id);.

Para nuestro ejemplo nos conformamos con unos simples indices Btree. Quedarian de la siguiente manera:


CREATE INDEX produccion_odin_id ON produccion_odin (id);
CREATE INDEX produccion_delta01_id ON produccion_delta01 (id);
CREATE INDEX produccion_delta01plus_id ON produccion_delta01plus (id);
CREATE INDEX produccion_delta02_id ON produccion_delta02 (id);


Bien, ahora procederemos a crear el juego de reglas para garantizar el llenado en cascada de los datos y que cuando estos caigan en la tabla maestra sean redirigidos a sus respectivas tablas.


-- Regla para produccion_odin
CREATE RULE produccion_odin_insert_rule AS
ON INSERT TO produccion WHERE
( id_modelo = 1 )
DO INSTEAD
INSERT INTO produccion_odin VALUES ( NEW.id,
NEW.no_serie,
NEW.id_modelo,
NEW.id_personal,
NEW.fecha_fabricacion,
NEW.fecha_salida);

-- Regla para produccion_delta01
CREATE RULE produccion_delta01_insert_rule AS
ON INSERT TO produccion WHERE
( id_modelo = 2 )
DO INSTEAD
INSERT INTO produccion_delta01 VALUES ( NEW.id,
NEW.no_serie,
NEW.id_modelo,
NEW.id_personal,
NEW.fecha_fabricacion,
NEW.fecha_salida);

-- Regla para produccion_delta01plus
CREATE RULE produccion_delta01plus_insert_rule AS
ON INSERT TO produccion WHERE
( id_modelo = 3 )
DO INSTEAD
INSERT INTO produccion_delta01plus VALUES ( NEW.id,
NEW.no_serie,
NEW.id_modelo,
NEW.id_personal,
NEW.fecha_fabricacion,
NEW.fecha_salida);

-- Regla para produccion_delta02
CREATE RULE produccion_delta02_insert_rule AS
ON INSERT TO produccion WHERE
( id_modelo = 4 )
DO INSTEAD
INSERT INTO produccion_delta02 VALUES ( NEW.id,
NEW.no_serie,
NEW.id_modelo,
NEW.id_personal,
NEW.fecha_fabricacion,
NEW.fecha_salida);



Ya con esto tenemos gestionada la metodologia para la inserción en multiples tablas, tambien es importante notar que se pueden usar triggers en vez de reglas para este fin.

Ahora procedemos a crear una vista que contendra todos los valores como si se tratase de una tabla enorme:


CREATE VIEW produccion_total AS
SELECT * FROM produccion_odin
UNION ALL SELECT * FROM produccion_delta01
UNION ALL SELECT * FROM produccion_delta01plus
UNION ALL SELECT * FROM produccion_delta02;


Con esto ya tenemos nuestro esquema de tablas particionado, solo nos falta habilitar el obtimizador de consultas para evitar la busqueda de algun dato en todas las particiones y eso se hace asi desde dentro de psql:

SET constraint_exclusion = on;

o modificando el postgresql.conf de la siguiente manera, anexando la siguiente linea:

constraint_exclusion = on

Pues ya con esto me despido y espero les sirva.

Indices Parciales en Postgresql

Postgresql soporta lo denominado indice parcial con expresiones arbitrarios el cual es un indice construido sobre un subconjunto de los registros de una tabla.

Un motivo para la utilización de este tipo de indices esta justificado con la siguiente premisa: si todas las consultas que a usted le resulten útiles caen dentro de un cierto rango ¿por qué construir un índice sobre toda la tabla y sufrir el costo de espacio y tiempo asociado a ello?

Un ejemplo de este tipo de indices quedaria de la siguiente forma:

CREATE INDEX sueldos_idx ON sueldos(sueldo) WHERE sueldo > 15000.00 and sueldo < 30000.00;

Aqui el indice se crea solo para los sueldos almacenados entre 15000.00 y 30000.00 y si en una fabrica la mayoria de los empleados recaen en esos sueldos, aqui es donde se utilizaria ahorrando espacio por el indice generado.

Saludos.

viernes, 10 de agosto de 2007

Cambiar el propietario de una tabla en PostgreSQL

Para cambiar el propietario de una tabla x en postgres nos valemos del comando alter para efectuar dicha operación, la sintaxis para este proposito seria de la siguiente manera:


ALTER TABLE tablax OWNER TO usuario_nuevo;


Para que la siguiente instrucción surta efecto solo basta ser el propietario de la tabla o ser el usuario PostgreSQL.

Saludos a todos.



miércoles, 1 de agosto de 2007

Configurar el protocolo SSL en Apache 2.2 con Ubuntu Feisty Fawn

Hola a todos, el dia de hoy voy a documentar el como instalar en nuestro ubuntu feisty fawn el protocolo SSL (Secure Socket Layer) para nuestro Apache 2.2.

A diferencia de lo que pensaba antes de hecharlo a andar, es muy facil instalarlo.

Pues comencemos.

1. Primero que nada necesitamos instalar el servidor web apache que en ubuntu y cualquier distribucion basada en debian es cosa de un simple apt-get.

# apt-get install apache2

2. Ahora nos toca habilitar el modulo de SSL en nuestro recien instalado apache.

#a2enmod ssl

3. Aqui deberiamos de poder crear el certificado ssl mediante el comando apache2-ssl-certificate, pero para nuestra desgracia, al parecer en esta versión de ubuntu no se incluyo y necesitamos realizar unos pasos adicionales para subsanar dicho error :( , y quedaria asi.

Necesitamos descargar el siguiente archivo: apache2-ssl.tar.gz y ya una vez descargado procedemos a descomprimirlo, lo cual nos deja dos archivos en nuestro directorio. Uno con el nombre de ssleay.cnf el cual deberemos copiar en /usr/share/apache2 y otro con nombre apache2-ssl-certificate que copiaremos a /usr/sbin, ahora solo falta crear el directorio en donde residira el certificado ssl y el cual es /etc/apache2/ssl.

Listo, con esto ya tenemos el comando para generar el certificado de autenticidad, y podemos proceder a configurar nuestro Apache2 con SSL :) .

4. Creamos nuestro certificado de la siguiente manera:

# apache2-ssl-certificate

El comando nos arroja la siguiente salida esperando algunas respuestas:


creating selfsigned certificate
replace it with one signed by a certification authority (CA)

enter your ServerName at the Common Name prompt

If you want your certificate to expire after x days call this programm
with -days x
Generating a 1024 bit RSA private key
........++++++
....................++++++
writing new private key to '/etc/apache2/ssl/apache.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:MX
State or Province Name (full name) [Some-State]:Distrito Federal
Locality Name (eg, city) []:Mexico
Organization Name (eg, company; recommended) []:Sistemas y Conectividad
Organizational Unit Name (eg, section) []:Sistemas y Conectividad
server name (eg. ssl.domain.tld; required!!!) []:localhost
Email Address []:webmaster@localhost


5. Ahora necesitamos crear algunos archivos de configuracion para apache y para eso nos valemos de cualquier editor de textos como emacs o vi.

Nos basamos en los archivos de configuracion estandar de apache en nuestro ubuntu de la siguiente manera:


cp /etc/apache2/sites-available/default /etc/apache2/sites-available/ssl
ln -s /etc/apache2/sites-available/ssl /etc/apache2/sites-enabled/ssl


Ahora modifiquemos el archivo /etc/apache2/sites-enabled/ssl con cualquier editor de textos y agreguemos el numero de puerto de escucha de Apache2 SSL y algunas cosas mas como habilitar la directiva SSLEngine a On y fijar la ruta de SSLCertificateFile a /etc/apache2/ssl/apache.pem:


# Agregar puerto 443 default para SSL en NameVirtualHost
NameVirtualHost *:443

ServerAdmin webmaster@localhost

# Modificar el DocumentRoot hacia el directorio
# que querramos para SSL
DocumentRoot /home/www/ssl/htdocs

Options Indexes FollowSymLinks MultiViews
AllowOverride All


# Opciones de configuracion de nuestro directorio SSL

Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
# This directive allows us to have apache2's default start page
# in /apache2-default/, but still have / go to the right place
#RedirectMatch ^/$ /apache2-default/


ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

AllowOverride None
Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all


ErrorLog /var/log/apache2/error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn

CustomLog /var/log/apache2/access.log combined
ServerSignature On

# Aqui agregamos el soporte SSL para nuestro apache asi como la ruta
# del certificado creado anteriormente.
SSLEngine On
SSLCertificateFile /etc/apache2/ssl/apache.pem

Alias /doc/ "/usr/share/doc/"

Options Indexes MultiViews FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
Allow from 127.0.0.0/255.0.0.0 ::1/128






6. Ahora necesitamos modificar el archivo: /etc/apache2/sites-enabled/000-default agregandole el puerto 80 al servidor web para las conexiones no seguras. El cambio quedaria asi:


# Puerto 80 predeterminado para el servidor web sin SSL
NameVirtualHost *:80

# Tambien aqui le agregamos el puerto 80

ServerAdmin webmaster@localhost

DocumentRoot /home/www/

Options Indexes FollowSymLinks MultiViews
AllowOverride All


Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
# This directive allows us to have apache2's default start page
# in /apache2-default/, but still have / go to the right place
#RedirectMatch ^/$ /apache2-default/


ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

AllowOverride None
Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all


ErrorLog /var/log/apache2/error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn

CustomLog /var/log/apache2/access.log combined
ServerSignature On

Alias /doc/ "/usr/share/doc/"

Options Indexes MultiViews FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
Allow from 127.0.0.0/255.0.0.0 ::1/128






Esos son los unicos cambios que se deben realizar en el archivo de default.

7. Ahora solo nos falta agregar el nuevo puerto (443) en el archivo /etc/apache2/ports.conf para que apache realice un fork() y cree el servidor a la escucha en ese puerto. El archivo ya modificado quedaria asi:


juliocs@andromeda:~$ cat /etc/apache2/ports.conf
Listen 80
Listen 443


8 Ya con esto solo nos falta reiniciar el apache con el comando:


# /etc/init.d/apache2 force-reload


Aqui muestro la salida del comando nmap contra localhost mostrando a nuestro apache con SSL habilitado:


juliocs@andromeda:~$ nmap localhost

Starting Nmap 4.20 ( http://insecure.org ) at 2007-08-01 05:53 CDT
Interesting ports on localhost (127.0.0.1):
Not shown: 1684 closed ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
111/tcp open rpcbind
139/tcp open netbios-ssn
443/tcp open https
445/tcp open microsoft-ds
631/tcp open ipp
902/tcp open iss-realsecure-sensor
977/tcp open unknown
2049/tcp open nfs
3306/tcp open mysql
5432/tcp open postgres

Nmap finished: 1 IP address (1 host up) scanned in 0.247 seconds



Ya por mi parte es todo y nos vemos pronto.



sábado, 28 de julio de 2007

Importar datos externos a nuestra base de datos PostgreSQL mediante un script PHP

Hola a todos, este documento bien podria ser la continuación del documento anterior "Importar datos externos a nuestra base de datos PostgreSQL mediante COPY" pero ahora nos toca usar PHP para la importación de datos CSV hacia nuestra querida base de datos PostgreSQL.

Primero que nada empezemos por definir nuestra tabla que contendra los datos. La tabla tiene las siguientes caracteristicas para el ejemplo en cuestion:

Tabla «public.clientes_csv»
Columna | Tipo | Modificadores
---------------------+------------------------+---------------
id | integer |
rfc | character varying(15) |
nombre_razon_social | character varying(80) |
direccion | character varying(120) |
telefonos | character varying(50) |

sicodelico=>


Y ahora pasamos a mostrar un fragmento del archivo de excel con los datos a importar.



Guardamos el archivo para excel en formato CSV, quedandonos un archivo de texto plano en formato ascii y separado por comas. Es vital recordar que debemos eliminar los encabezados o datos que no deseemos importar a nuestra base de datos.

El archivo quedaria de la siguiente forma:


289,"ROAB","ABIGAIL ROCHA","MIRAMONTES","4554-4455"
311,"AHE821025DLA","ABUD HERMANOS S.A DE C.V.","SANTO DEGOLLADO 895 TEQISQUIAPAN SAN LUIS POTOSI","6766-7788"
26,"MBA831017P83","ACABADOS CONTEMPORANEOS","AV.DIVICION DEL NORTE #2001 COLONIA SANTA CRUZ ATOYAC DELEGACION BENITO JUAREZ","5677-5644"
50,"ASH020827694","ACABADOS SHUMA S.A DE C.V","25 PONIENTE 3513 BELICIARIO DOMINGEZ PUEBLA PUEBLA","2345-1033"
38,"AUHY760723CJA","AGUILERA HERNANDEZ YANET","AV.ERMITA IZTAPALAPA #655 PROGRESO DEL SUR IZTAPALAPA MEX.DF","1234-4567"
354,"MAROAA","ALAN AXEL MARIN ROBLES","VENDEDOR DE DELTA","3458-4564"
326,"ABC051019AX6","ALBERCAS BOMBAS Y CALENTADORES S.A DE C.V.","TANKAH MZA 11 LOTE 16 SMZA 27 POR AV. BENITO JUAREZ CANCUN Q.ROO","1234-5676"
41,"BOMA720502825","ALEJANDRA BOLAÑOS MORALES","LIBERTAD #58 LOCAL 4 Y 5 SAN SIMON TICUMAC DEL. BENITO JUAREZ","9890-5678"
207,"ERETQL","ALEJANDRA TERESA HERNANDEZ","CHALCO # 26 COLONIA EL CONDE NAUCALPAN EDO DE MEXICO","1234-5643"
212,"ONAL","ALEJANDRO GONZALEZ","VENTA DE CALENTADOR CON DESCUENTO","4532-2332"
344,"COCA601222LKG","ALEJANDRO SALVADOR COLINAS COSIO","TUXTLA GUTIERREZ CHIAPAS","2332-4554"


El archivo tiene el nombre de clientes.csv, ahora procedamos a mostrar el codigo PHP que nos servira para importarlo a nuestra base de datos mediante un formulario.


<?php
//
// Hecho Por: Julio Cesar Sánchez González - juliocesar_dark@hotmail.com
// Fecha: 27 / Jul / 2007.
//
// El programa se distribuye como tal, sin garantías de ningun tipo y
// esta liberado bajo la licencia publica general de GNU (GPL).
//
?>

<html>
<head>
<title>Importación de un archivo CSV de excel hacia
PostgreSQL</title>
</head>
<table>
<form action="" method="POST" enctype="multipart/form-data">
<tr>
<td>Subir archivo CSV:</td>
<td><input type="file" name="archivo_csv"
id='archivo'></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="E N V I A R">
<input type="reset" value="C A N C E L A R">
</td>
</tr>
</form>
</table>
</body>
</html>

<?php

$file_upload = $_FILES["archivo_csv"]["name"];
$tmp_name = $_FILES["archivo_csv"]["tmp_name"];
$size = $_FILES["archivo_csv"]["size"];
$tipo = $_FILES["archivo_csv"]["type"];

if($size > 0){
echo "<h3>Archivo origen: $file_upload</h3>";
echo "<h3>Archivo destino: $tmp_name</h3>";
echo "<h3>Tamaño del archivo: ".($size/1024)." Kb.</h3>";
echo "<h3>Tipo MIME: $tipo</h3>";

// Comprobamos si el archivo a subir es CSV
if($tipo == "text/csv"){
$conex = "host=localhost port=5432 dbname=sicodelico \
user=juliocs password='foobar'";
$CONN = pg_connect($conex) or die ("Error en el socket \
de conexión");

echo "Conectando con la base de datos...<br>";
echo "Insertando los datos recuperados del archivo \
en la base de datos...<br>";

$fp = fopen($tmp_name, "r");

// Procesamos linea a linea el archivo CSV y
// lo insertamos en la base de datos
while($datos = fgetcsv ($fp, 1000, ",")){
$query = "INSERT INTO clientes_csv (id, rfc, \
nombre_razon_social, direccion, \
telefonos) VALUES ('$datos[0]', '$datos[1]', \
'$datos[2]', '$datos[3]', '$datos[4]')";

//echo $query;

pg_query($CONN, $query);
}

pg_close($CONN);
}else{
echo "<h3>El formato para el archivo especificado \
no es válido.</h3>";
}
}
?>


Aqui tenemos una imagen del formulario en funcionamiento:



y esta seria la salida de un select en el monitor psql de postgres con los datos ya importados:



Creo que eso es todo por hoy, ademas que ya son las 2:18 de la mañana y aunque suelo trabajar de noche mañana tengo una cita de negocios. Una ultima cosa, el codigo PHP lo tuve que cortar con "\" diagonal invertida ya que no se apreciaba bien del todo por el ancho del blog :( .

Buenas noches a todos y hasta la proxima.

jueves, 26 de julio de 2007

Compilar programas en "C" para acceso a datos PostgreSQL

Para compilar un programa escrito en C que emplee la libreria libpq de PostgreSQL es necesario tener instalado los archivos de desarrollo includes para C.

En el siguiente caso probado en Fedora Core 4 funcionaba instalado desde las fuentes.

gcc testpq.c -I/usr/local/pgsql/include -L/usr/local/pgsql/lib -lpq -o testpq

Pero para ubuntu instalado mediante apt-get quedaria de la siguiente forma:

gcc libpqe.c -o libpqe -I/usr/include/postgresql/ -L/usr/include/postgresql -lpq

A continuacion pongo un pequeño programa en C que accesa a una base de datos postgresql y sirve como ejemplo para probar la compilacion de codigo C con las librerias libpq:


/*
/ Programa : sqlt.c
/ Autor : Julio Cesar Sánchez González (juliocesar_dark@hotmail.com) GNU GPL.
/ Fecha : 25 - Mayo - 2006.
/ Ultimo Update: 25 - Mayo - 2006.
/ Revisión : 2
/ Descripción : Obtiene un conjunto resultado de una base de datos postgres proporcionandole la consulta y la base.
*/

#include
#include
#include "libpq-fe.h"
#include

void exit_nicely(PGconn *);

int main(int argc, char *argv[]){

if(argc != 5){
perror ("Sintaxix: sqlt <\"query\">\n");
exit(EXIT_FAILURE);
}

char *pghost,
*pgport,
*pgoptions,
*pgtty,
*dbname,
*query,
*cursor_command,
*login,
*pwd;
int nFields;
int i, j;

pghost = argv[1];
dbname = argv[2];
login = argv[3];
pwd = NULL;
query = argv[4];


PGconn *conn;
PGresult *result;

// pghost = "localhost";
pgport = NULL;
pgoptions = NULL;
pgtty = NULL;
// dbname = "memoria_sql";

//conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbname);
conn = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbname, login, pwd);

if(PQstatus(conn) == CONNECTION_BAD){
fprintf(stderr, "Conexión fallida con la base de datos %s\n", dbname);
fprintf(stderr, "%s", PQerrorMessage(conn));
exit_nicely(conn);
}

// Transaccion
result = PQexec(conn, "BEGIN");

if(!result || PQresultStatus(result) != PGRES_COMMAND_OK){
fprintf(stderr, "Imposible realizar transaccion\n");
PQclear(result);
exit_nicely(conn);
}

PQclear(result); // Limpiamos el result para evitar fugas de memoria

cursor_command = (char *) malloc((size_t)1024*sizeof(char));

sprintf(cursor_command, "DECLARE mycursor CURSOR FOR %s", query);

result = PQexec(conn, cursor_command);

if(!result || PQresultStatus(result) != PGRES_COMMAND_OK){
fprintf(stderr,"Declaración de CURSOR fallida\n");
PQclear(result);
exit_nicely(conn);
}

PQclear(result);

result = PQexec(conn, "FETCH ALL in mycursor");

if(!result || PQresultStatus(result) != PGRES_TUPLES_OK){
fprintf(stderr,"El comando no regreso ninguna tupla.\n");
PQclear(result);
exit_nicely(conn);
}


nFields = PQnfields(result);

for(i = 0; i < PQntuples(result); i++){

printf ("\n\n=========================\n\t=> Registro: %d\n=========================\n\n", i+1);

for(j = 0; j < nFields; j++){
printf("%-15s: %-15s\n", PQfname(result, j), PQgetvalue(result, i, j));

//printf("\n");
}
}

PQclear(result);

result = PQexec(conn, "CLOSE mycursor");

PQclear(result);

// Aseguramos la transaccion
result = PQexec(conn, "COMMIT");

PQclear(result);

PQfinish(conn);

return 0;
}


void exit_nicely(PGconn *conn){
PQfinish(conn);
exit(1);
}




Saludos...

Tiempo fugaz

Hoy desperte con un dejo de tristeza, al mirar que todo lo construido se derrumba, al pensar en mis viejos amigos, antiguos amores, que se yo, tanto nos perdemos con el paso del tiempo y ni siquiera nos damos cuenta.

Solo pasa el tiempo, o el tiempo nos pasa, no lo se, pero a todo esto le llamamos vida. Vivimos creyendo que somos importantes para la vida, pero la vida es mas importante para nosotros.

Somos tan egoistas, pensando en el pasado y queriendo regresar a el, que no nos damos cuenta a lo mucho que renunciamos en el presente.

martes, 24 de julio de 2007

Cambiar los passwords de usuario en PostgreSQL

Primero que nada nos convertimos en superusuario:

$su root

Ya teniendo privilegios nos convertimos en usuario postgres que es el superusuario de la base de datos pero un simple mortal para el filesystem.

#su postgres

ya como postgres solo falta entrar en la base de datos principal "template1"

$psql template1

y de ahi, cambiamos el password del usuario en cuestion.

alter user nombre_usuario with encrypted password "x password";

y yeah, asi de facil.

Bye...

Problemas con parseInt("08") & parseInt("09") de Javascript

El problema se suscita cuando necesitamos convertir la cadena de texto "08" o "09" en un valor entero y al emplear parseInt nos regresa el valor 0. Pero ¿Porque?, pues simple, parseInt emplea como estandar la base de codificación octal y en octal no existen los valores 08 y 09, para solucionarlo debemos de emplear la notación complementaria de parseInt.

Como un ejemplo vale mas que mil palabras, pues aqui esta el ejemplo:

var m = parseInt("08", 10);

con esto obtenemos el valor convertido en entero de la cadena "08" en "m".

Saludos...

sábado, 14 de julio de 2007

Obtener el numero de dias que lleva transcurrido el año en PostgreSQL (Fecha jualiana)

Con la siguiente query, obtenemos el numero de dias transcurridos del año en curso. La solución emplea aritmetica de fechas y fue probada en PostgreSQL 8.2 sobre Ubuntu Linux.

SELECT date_trunc('days', now() - (select cast(date_trunc('year', current_date) as date) as curr_year)::date) + interval '1 day' as dias_transcurridos;


Otra forma simplificada de esto seria mediante la funcion to_char() de postgresql y quedaria de la siguiente forma:

SELECT to_char(now(), 'ddd');

Saludos ;)

miércoles, 27 de junio de 2007

INSERT ... RETURNING y Conociendo el valor insertado en PostgreSQL

Algunas veces nos topamos con la necesidad de recuperar un cierto valor despues de una insercion en postgresql, como puede ser el valor asignado a un id de forma automatica mediante nextval o alguna valor seteado manualmente. A continuación muestro las diferentes formas para lograr esto sin un maximo de esfuerzo:

Supongamos que tenemos creadas la secuencia: clientes_id_seq y la usaremos dentro de una inserción.


INSERT INTO clientes (id, nombre, telefono)
VALUES (nextval('clientes_id_seq'), 'Juan Pérez','3455-6678');


Para conocer el id insertado podemos usar la funcion: currval() de la siguiente forma:


select currval('clientes_id_seq');


Otro metodo alternativo, y sobre todo cuando no manejamos secuencias es emplear INSERT RETURNING cuya sintaxis es la siguiente y que solo esta disponible en las versión 8.2 de PostgreSQL:

INSERT INTO clientes (id, nombre, telefono) values (5,'Juan Pérez','3455-6678') RETURNING id;

Tal vez aqui no se note la importancia del insert returning pero si el insert es dinamico mediante un script en algun lenguaje de programación la utilidad salta a simple vista.

Habilitar o desabilitar Triggers en PostgreSQL

Existen diversas formas para habilitar o desabilitar los triggers en postgresql, sobre todo de version a version.

A continuacion se muestran ejemplos en diferentes versiones.

Para PostgreSQL 8.1 o posterior es muy simple, solo basta con:


ALTER TABLE nombre_tabla ENABLE/DISABLE TRIGGER mi_trigger;


La cosa se complica con versiónes anteriores a la version 8.0 ya que tenemos que modificar los catalogos del sistema, como se muestra a continuacion:

Desabilitarlos

UPDATE pg_catalog.pg_class SET reltriggers = 0 WHERE oid = 'nombre_tabla'::pg_catalog.regclass;

Habilitarlos

UPDATE pg_catalog.pg_class SET reltriggers = (SELECT pg_catalog.count(*) FROM pg_catalog.pg_trigger WHERE pg_class.oid = tgrelid) WHERE oid = 'nombre_tabla'::pg_catalog.regclass;

Y eso es todo por el momento, saludos.

martes, 26 de junio de 2007

Ejemplo de frontend para el comando WHOIS en PHP y Linux con exec()

El uso de la instrucción exec() de PHP es muy poderoso y peligroso ya que mediante dicha funcion es posible accesar al sistema operativo del servidor en donde esta instalado PHP.

El siguiente ejemplo en PHP muestra como hacer una interfaz de usuario sencilla para el cliente WHOIS en sistemas LINUX o UNIX y es una implementación muy sencilla que muestra el uso de la instrucción exec() de PHP que como su contraparte en Lenguaje C o Perl realiza la misma acción.


<html>
<head><title>Whois Frontend</title></head>
<body>
<form name='whois' action="" method="POST">
<table>
<tr>
<td>Dominio a Consultar:</td>
<td><input type="text" name="fqdn" value="google.com" size="30"> <input type="submit"></td>
</tr>
</table>
</form>
<?php
// Con este bucle creamos las variables dinamicamente enviadas mediante POST y asi no es necesario
// escribirlas una o una, aunque en este ejemplo es trivial ya que se usa una sola variable fqdn existiran
// programas en la vida real que manejen cientos de variables simultaneamente.
foreach ($_POST as $clave => $valor)
$$clave= $valor;

$comando= "whois $fqdn";

exec($comando, $res);

echo "<pre>";
foreach($res as $line)
echo $line."<br>";
echo "</pre>";

?>
</body>
</html>

lunes, 25 de junio de 2007

Acentos en PHP, PostgreSQL y Apache 2

Es muy facil toparnos con problemas a la hora del despliegue de información con los caracteres latinos como el acento, las dieresis, las ñ, etc. El problema es debido a la codificación estandar en ambientes Linux que es UNICODE o UTF8 como tambien le llaman. Aunque el manejar UNICODE es una gran ventaja por el almacenamiento multilingüe, aveces parece todo lo contrario ya que la codificación estandar en windows es ISO-8859-1 al menos para America Latina y otros paises que manejan el español como lengua predeterminada.

Aqui la solución es configurar nuestro soporte para ISO-8859-1 en PostgreSQL, Apache y PHP para que nuestras aplicaciones web y bases de datos manejen el mismo charset.

Para habilitar dicho charset en PHP es muy simple, solo basta con editar el archivo php.ini almacenado dentro de /etc en la mayoria de las distribuciones linux y descomentar la linea como se muestra a continuación:

default_charset = "iso-8859-1"

Para habilitar ahora el soporte en Apache basta con editar el archivo httpd.conf o alguno relacionado segun la distribución, en mi caso en ubuntu seria el archivo /etc/apache2/apache2.conf

y descomentar la linea siguiente como se muestra a continuación:

AddDefaultCharset ISO-8859-1

ya por ultimo solo nos faltaria crear nuestra base de datos usando el tipo de codificación latina como se muestra a continuación:

createdb -U postgres --encoding=Latin1 --owner=propietario mibasededatos

Ya con esto tenemos funcionando nuestro servidor web y nuestra aplicación con acceso de datos en ISO-8859-1.

Arrancar EMACS en modo consola dentro de XTERM

Para poder trabajar con emacs desde una consola sin ejecutar automaticamente el xemacs, esto es que se abra el editor emacs en modo terminal como cuando estamos dentro de alguna TTY solo basta con redirigir el modo grafico con el siguiente comando desde el shell:

$ export DISPLAY=

Y listo, emacs ya no se abrira en una ventana por separado, sino dentro de la terminal.

Pasos a seguir para modificar el charset interno (UTF8 a ISO-88591) del cluster de postgresql en ubuntu.

Primero se preguntaran ¿para que cambiarlo?, ¿que gano?, bueno, pues lo mismo pensaba yo, hasta un infortunado dia que necesite usar la funcion upper incorporada dentro de postgresql en un trigger y me di cuenta que la letra acentuada aparecia en minuscula y las demas letras aparecian bien en mayusculas y lo mismo pasaba con las ñ y las dieresis ö, pues bien, lo primero que se me ocurrio es ver si se trataba de un bug o solo era problema mio de configuración. Pues bien mande un correo a la lista de postgresql y el buen Alvaro Herrera me confirmo que en su sistema trabajaba bien la funcion upper y lower, asi que descarte el problema del bug, hice pruebas y me di cuenta que con Unicode si trabajaba bien dicha funcion pero no con ISO-8859-1 entonces otro buen compañero de la lista de nombre Alejandro Gasca me comento que los locale podrian estar mal configurados.

Como muchos sabran ubuntu emplea casi para todo UTF8 y ahi estaba el problema, pues despues de mucho googlear y de investigar me tope con el comando locale -a que muestra los charset instalados en el sistema y me di cuenta que por ningun lado aparecia ISO-8859-1.

Pues segui googleando y me tope que era muy facil agregar dicho charset, solo bastaba con editar el archivo /var/lib/locales/supported.d/es y agregar el siguiente texto en una nueva linea:

es_MX.ISO-8859-1 ISO-8859-1

Guardamos cambios y generamos la nueva lista de charsets con:

locale-gen

y listo, ya tenia la codificación ISO-8859-1 en mi sistema con ubuntu, ahora seguia lo bueno, reconstruir el cluster de postgresql, que como todos sabemos viene preempacado en ubuntu y se instala solito, tal como esta. Pues aqui tienen los pasos y espero que les funciona como a mi.

1.- Respaldamos todas las bases si existen ;)

2.- Paramos el ORDBMS Postgresql con:
/etc/init.d/postgresql-8.2 stop

3.- Nos ubicamos en el directorio de datos del cluster:
cd /var/lib/postgresql/8.2

Un leve vistazo mediante ls -alF en el directorio pgdata nos damos cuenta que es un vinculo simbolico :( y que apunta a la ruta antes citada.

4.- El directorio "main" contiene el cluster de la base de datos con codificación UTF-8, el directorio main lo renombramos para tener un punto de restauración si algo falla.

mv main main.old

5.- Creamos un nuevo directorio main para que el script de inicio de ubuntu ni lo note ;)

mkdir main

y cambiamos al propietario de dicho directorio con:

chown -R postgres.postgres main

6.- Ejecutamos initdb que en ubuntu feisty-fawn esta en: /usr/lib/postgresql/8.2/bin/ y ya con el nuevo charset ISO-8859-1

su postgres -c '/usr/lib/postgresql/8.2/bin/initdb -U postgres --locale=es_MX.ISO88591 --encoding=Latin1 --lc-collate=Latin1 -D /var/lib/postgresql/8.2/main'

7.- Ya por ultimo creamos las ligas simbolicas server.crt, server.key y root.crt necesarias para nuestro guion /etc/init.d/postgresql-8.2 de nuestro ubuntu.

ln -s /etc/postgresql-common/root.crt root.crt
ln -s /etc/ssl/certs/ssl-cert-snakeoil.pem server.crt
ln -s /etc/ssl/private/ssl-cert-snakeoil.key server.key

8.- Y listo, iniciamos nuevamente el servicio de postgresql y somos muy felices porque ya tenemos nuestro postgresql configurado con el charset ISO-8859-1.

/etc/init.d/postgresql-8.2 start

Saludos a todos :)

Importar datos externos a nuestra base de datos PostgreSQL mediante COPY

Algo muy importante en nuestra base de datos, es sin duda eso, los datos, ¿que hariamos sin ellos?, ¿que proposito tendria entonces tener una base de datos?

Muy bien, nuestra base de datos ya esta creada, tenemos un esquema relacional perfecto y tenemos normalizadas las tablas, ahora necesitamos poblar dichas tablas, pero no escribirlas de una en una.

Supongamos que la información la conseguimos en formato digital o es información almacenada en un archivo de hoja de calculo o algo por el estilo.

Aqui necesitamos primero que nada un formato estandar para poder mover la información de un formato propietario (por ejemplo excel, xls) a nuestras tablas de la base de datos, en este caso las tablas creadas previamente en postgresql.

Ese formato estandar se llama "CSV" o valores separados por comas.

Veamos un ejemplo de un archivo en excel que contiene algunos de los codigos postales de la Ciudad de México.

Archivo: CodigosPostalesMexicanos.xls



Pues bien, este archivo de excel lo queremos insertar dentro de nuestra base de datos ahora el problema es como lo hacemos. Lo bueno es que la solución es muy facil, simplemente lo guardamos como archivo de texto separado por comas o CSV y a continuación lo abrimos con un editor de texto y eliminamos todo lo que no tenga que ver con la información que vamos a importar, como por ejemplo encabezados de columna, etc.

Archivo: codigos_postales.csv


"d_codigo","d_asenta","d_tipo_asenta","D_mnpio","d_estado"
"01000","San Angel","Colonia","Alvaro Obregon","Distrito Federal"
"01010","Los Alpes","Colonia","Alvaro Obregon","Distrito Federal"
"01020","Guadalupe Inn","Colonia","Alvaro Obregon","Distrito Federal"
"01028","Secretaria de Contraloria y Desarrollo Administrativo","Gran usuario","Alvaro Obregon","Distrito Federal"
"01029","Infonavit","Gran usuario","Alvaro Obregon","Distrito Federal"
"01030","Axotla","Pueblo","Alvaro Obregon","Distrito Federal"
"01030","Florida","Colonia","Alvaro Obregon","Distrito Federal"
"01040","Campestre","Colonia","Alvaro Obregon","Distrito Federal"
"01048","Las Aguilas","Unidad habitacional","Alvaro Obregon","Distrito Federal"


Si notan la primera linea contiene el encabezado que aparecia en excel, es muy importante eliminar esa o las lineas que no sean necesarias para evitar errores a la hora de importarlas, y quedaria asi:


"01000","San Angel","Colonia","Alvaro Obregon","Distrito Federal"
"01010","Los Alpes","Colonia","Alvaro Obregon","Distrito Federal"
"01020","Guadalupe Inn","Colonia","Alvaro Obregon","Distrito Federal"
"01028","Secretaria de Contraloria y Desarrollo Administrativo","Gran usuario","Alvaro Obregon","Distrito Federal"
"01029","Infonavit","Gran usuario","Alvaro Obregon","Distrito Federal"
"01030","Axotla","Pueblo","Alvaro Obregon","Distrito Federal"
"01030","Florida","Colonia","Alvaro Obregon","Distrito Federal"
"01040","Campestre","Colonia","Alvaro Obregon","Distrito Federal"
"01048","Las Aguilas","Unidad habitacional","Alvaro Obregon","Distrito Federal"


Ya hecho lo anterior lo guardamos y procedemos a crear la tabla en nuestra base de datos postgresql como se muestra a continuación:


\d codigos_postales
Tabla «public.codigos_postales»
Columna | Tipo | Modificadores
-------------------+------------------------+---------------
cp | character(5) |
asentamiento | character varying(255) |
tipo_asentamiento | character varying(120) |
municipio | character varying(120) |
estado | character varying(120) |


La forma de crear el esquema anterior es muy simple ya que utiliza SQL estandar y en postgres quedaria como sigue:


CREATE TABLE codigos_postales (
cp char(5),
asentamiento varchar(120),
tipo_asentamiento varchar(120),
municipio varchar(120),
estado varchar(120)
);


Ya lo unico que nos falta es poblar dicha tabla con el comando COPY y CSV. Pues manos a la obra, y queda asi:

COPY codigos_postales FROM '/tmp/codigos_postales.csv' DELIMITERS ',' CSV;

Recordemos que el comando COPY lo escribimos dentro de psql y que el propietario del archivo codigos_postales debe de poder ser leido por el usuario postgres en cuestion, en unix con un simple chmod 644 /tmp/codigos_postales.csv quedaria para poder ser leido por el postmaster de postgresql. Otra cosa importante a notar es que el unico que tiene permiso para hacer esta importación es el usuario postgres y debe de tener tambien permiso de lectura sobre el directorio en cuestion, en este caso /tmp. En windows la ruta del archivo es sustituida por la ruta correspondiente en Windows, por ejemplo "c:\temp\codigos_postales.csv".

Esta forma de importación es muy importante sobre todo cuando queremos migrar datos entre distintas plataformas o bases de datos que no nos ofrezcan alguna herramienta de migración mediante acceso a datos como ADO, ODBC, etc. O si lo que queremos es importar datos de archivos estadisticos o de excel.

Si ahora lo que queremos es crearle una llave primaria a la tabla codigos postales, lo que podemos hacer es jugar un poco con los datos de la siguiente forma:

ALTER TABLE codigos_postales add column id serial;

Con esto logramos crear una columna nueva de nombre "id" y es de tipo serial que ademas de ser un tipo entero tambien crea una secuencia implicita para poder incrementar el id de cada registro de una forma facil y segura.

ahora necesitamos poblar ese campo id si es que postgresql no le asigno ya un numero, seria de la siguiente forma: UPDATE codigos_postales SET id = nextval('codigos_postales_id_seq');

Ya nadamas nos falta aplicar la restriccion de llave primaria y eso lo logramos con: ALTER TABLE codigos_postales ADD PRIMARY KEY (id);

Y con esto terminamos nuestro ejemplo de importación mediante CSV con el comando COPY.

Crear, alterar o reiniciar una secuencia en PostgreSQL

En postgresql como en oracle para poder generar un numero unico facilmente necesitamos de lo que se conoce como secuencia. Para los usuarios de MySQL esto es algo nuevo ya que en mysql para un campo numero autoincrementable solo basta con poner null, aqui necesitamos algo mas de trabajo pero sin duda tener una secuencia es algo muy poderoso.

Para poder crear una secuencia en postgresql nos valemos del comando create sequence, y como un ejemplo vale mas que mil palabras, pues aqui tenemos el ejemplo completo.


Creando la secuencia serie:

Ya dentro del monitor psql tecleamos:


CREATE SEQUENCE foo start 100;


Si queremos borrarla, basta con hacer DROP SEQUENCE foo; y si lo que queremos es reiniciarla a un valor lo podemos hacer de dos formas.

La primera es mediante la función setval que se emplearia de la siguiente manera: SELECT setval('foo',1500,'t');. Si lo que queremos es reiniciarla para que empieze nuevamente desde el primer valor en este caso podemos borrarla o reiniciarla de la siguiente forma: ALTER SEQUENCE foo restart 1;

Con esto damos un primer vistazo a las secuencias que seran parte fundamental para el manejo de llaves primarias.

domingo, 24 de junio de 2007

Registrar el lenguaje PL/PGSQL

Aveces con el uso cotidiano de postgresql nos surge la necesidad de poder usar funciones, procedimientos almacenados o triggers dentro de nuestra base de datos pero casi siempre al menos en linux el soporte para plpgsql necesita habilitarse.

Pues aqui tienen los pasos para registrar el buen lenguaje PL/PGSQL similar al PLSQL de Oracle.

Como usuario Postgres efectuamos los siguiente en el bash o interprete de comandos:

$ createlang plpgsql template1

Asi ya queda generado en la plantilla principal y aplica a todas nuestras bases de datos. O si lo que quieren es crear el lenguaje en una base de datos que ya tengan es la misma sintaxis, solo que en vez de template1 sera el nombre de la base que usen, por ejemplo:

$ createlang -U postgres plpgsql mibasededatos

Aqui el operador -U le indica al comando que se conecte con la base de datos como usuario postgres.

Saludos...

Cambiar el password de un usuario en postgresql

Para poder asignarle un password a un usuario o incluso cambiarlo en la base de datos PostgreSQL solo necesitamos realizar los siguientes pasos:

1. Nos convertimos en usuario root, en linux por supuesto, aunque en windows tambien funciona no hay como postgresql en linux.

$ su root

2. Ahora nos convertimos en el usuario postgres que es el administrador del gestor relacional.

# su postgres

Ya por ultimo entramos al monitor de psql en la base de datos principal "template1"

$ psql template1

y aqui dentro escribimos:

alter user nombre_usuario with encrypted password 'password';

y listo, asi podemos cambiar nuestras contraseñas las veces que queramos en PostgreSQL.

Entre el cielo y el infierno

Esta es una copia de mi archivo motd de mi sistema y un poco de ascii art :)

Linux geminis 2.6.15-26-686 #1 SMP PREEMPT Thu Aug 3 03:13:28 UTC 2006 i686 GNU/Linux


..............
................
....................
....::.... ....
....::::::::..
....::;;;;ii;;::::
..........::::........::::;;iittttii;;::..
....::::,,,,;;;;;;;;;;;;;;;;iittjjLLLLLLjjtt;;::..
....::::;;iiiittttttttttttttttttttffLLGGDDGGLLjjtt;;::..
..::::iittLLLLGGGGDDDDDDDDGGGGGGGGGGGGDDWWWWEEDDGGfftt;;::..
....,,iittLLDDWWWWWWWW##WWWWWWWWDDDDDDDDWWWWWWWWWWDDGGjjtt,,::..
..::iittGGDDWW##################WWWWWWWWWWWWWWWWWWWWDDGGffii;;::..
..::;;ttffGGWW######################WWWWWWWW########WWWWDDLLjjii::..
..,,iijjLLDDWW######################WWWWWWWWWWWWWWWWWWWWDDGGLLttii::..
..::;;iijjLLGGDDWW##################WWWWWWWWWWWWWWWWWWWWWWDDGGLLjjii;;::..
..::;;iijjLLGGDDDDWWWW##########WWWWWWWWWWWWWWWWWWWWWWWWWWDDGGLLjjttii::::
....::iiiijjLLLLGGDDDDWWWWWWWWWWWWWWWWWWWWDDDDDDDDWWWWWWWWWWDDGGLLffttii,,::..
..::::iittjjffLLGGDDDDWWWWWWWWWWWWDDDDDDDDDDDDDDDDDDWWWWDDDDDDGGLLjjttii;;::....
..::::iittjjLLLLGGDDDDWWWWWWWWWWWWDDDDDDDDDDDDDDDDDDEEDDDDDDDDGGLLjjttii;;::::..
..::,,iittffLLLLGGDDDDWWWWWWWWWWWWWWDDDDDDDDDDDDDDWWWWWWDDDDDDGGLLffttttii;;::..
..::,,iijjLLLLGGGGDDDDWWWWWWWWWWWWWWWWDDDDDDDDDDWWWWWWWWWWEEDDDDGGLLjjttii;;::..
..::,,ttjjLLLLGGGGDDKKWWWWWW##WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWDDGGGGLLjjttii::::..
..::,,ttjjLLLLGGDDDDEEWWWWWW######WWWWWWWWWWWWWWWWWWWW##WWWWWWWWDDGGLLLLttii;;::..
..::;;ttjjLLGGGGDDDDDDWWWWWW########WWWWWWWWWWWWWWWW######WWWWWWDDDDGGLLjjtt;;::..
..::iittjjLLGGGGGGDDDDDDWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWDDDDGGLLffttii;;....
..::iittjjLLGGGGGGGGDDDDDDDDWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWDDDDGGGGGGLLffjjttii::..
..::iittjjLLGGGGGGGGGGGGGGGGGGDDDDDDDDDDDDDDDDDDDDDDDDDDGGGGGGGGGGLLLLLLttttttii,,::
..::;;iittjjffffffffffffffffLLLLLLLLLLLLGGGGLLLLGGGGLLLLLLLLLLffjjjjttttttiittii;;::..
..::,,;;iiii;;;;;;;;;;;;iiiiiiiiiittttttttjjttttttttttttiiiiii;;,,::;;;;iiiiiiii;;::..
..::::,,::::::::::::::::::::::::,,;;;;iiiiiiiiiiii;;;;;;,,::::::::......::::::::::::..
..::::::::::::........ ........::::::::;;;;;;;;,,::::........ ............
..::::::::.......... ......::::::::;;;;,,::......
..::::.... ....::::iiii,,::..
..::::.... ..::,,iiii;;::..
..::.... ..;;;;ttttii::..
..::.... ::iittLLfftt,,..
..::::.. ..::ttLLDDGGjj;;::
..::::::.. ..;;ttGGDDDDLLii::
..::;;::::.... ..,,iiffDDWWDDLLtt;;..
..,,ii;;::::::.. .. ......::::iiiiLLDDWWEEGGttii,,.. ......
..::;;iiii;;;;,,,,..::::::::::::;;iiiiiijjGGDDWWDDGGjjttii;;::::........ ............::,,::..
..::;;iittiiiiii;;;;;;,,;;;;;;iiiiiiiittLLGGDDWWDDGGLLttiiiiii;;::::::::......::::::::;;ii;;::
..::;;iittttttttttttttttjjjjjjjjjjttttffLLDDEEWWGGLLLLjjttttttttttiiiiii;;iiiiiiiiiittttttii,,..
..::;;iiiittttjjffLLLLLLGGLLLLLLffjjjjffffGGDDWWGGffjjttttttttttjjffjjjjttjjttttjjjjffjjttii;;::
..,,iiiittttjjffLLGGGGDDDDDDGGGGLLLLffLLLLGGDDEEGGjjiiiiiittttjjffLLGGGGGGGGGGGGGGGGLLLLjjttii::
::;;ttttjjffLLLLGGDDDDDDDDDDGGLLLLffLLLLGGDDDDGGjjttiiiittttttffLLGGDDDDDDDDGGGGGGLLLLffjjii,,
..::ttjjjjLLLLLLGGDDKKWWDDDDGGLLLLLLLLLLGGDDDDGGjjttttiittttttjjLLGGLLGGDDDDGGGGGGLLLLLLjjtt::
..;;ttjjffLLLLGGDDDDEEDDDDGGLLLLLLLLLLGGGGDDGGLLjjttttttttttttjjLLLLGGGGGGGGGGGGLLLLfftt;;::
::;;ttjjLLLLGGGGDDDDDDGGLLLLLLffLLLLGGGGDDLLLLjjttttttttttttjjffLLLLLLLLLLLLLLLLffttii::..
::;;iijjjjLLGGGGGGGGGGLLLLLLjjLLffLLGGDDffjjttiittttttttttttttjjLLLLLLLLLLLLjjtt;;::..
..::;;iijjLLLLGGGGLLLLLLLLLLjjttttjjLLGGttii;;::ttttttiiiittjjjjjjjjjjjjjjjjttii::..
::::,,iijjffLLLLjjjjjjtttttt::::,,ttjj::.. ::iiiiii;;iiiiiittttttttttttii::..
::::::,,ttjjffffjjttttiiiiii;;::::;;ii,,::::;;;;;;;;;;;;iiiittttttttiiii,,
..::::::;;ttjjjjttttiiii;;;;;;;;;;;;;;::::::::::::,,,,;;iiiitttttt;;::....
..::::::::iijjjjjjttttii;;;;,,::::::::..........::::,,;;iittttttii::......
....::::::iijjLLjjjjttttii;;::::...... ..::,,;;iiiitttttt::::::::..
....::::::iittffjjffjjttiiii,,::.... ..::;;;;iittjjttii::;;,,::..
....::::::;;ttttttffjjttttii;;,,::.... ....::;;iiiittttjjtt::::::::::
....::::::,,iittttjjjjjjtttt;;,,::::......::::;;;;iiiittttttii::,,::::..
..::::::::;;;;iiiitttttttt;;;;;;::::::::::;;;;iiiiiiiittii;;::::::::..
..::::::::::::;;;;iiiiiiii;;;;;;,,::::::,,;;;;iiii;;iiii,,::::::::::..
..::,,::::::::::::;;;;::::::::::::::::::::::::::;;::::::::::::::::::..
..::,,::::::::::::,,::::::::::::::::::::::::::::;;::::::::::::::::::..
..::::::::::::::::::::::::..::::::::::::::::..::::::::::::::::::::..
..::::::::..::::,,::::::::,,,,..::::::::::::::::::::::::::::::::..
..::::::::::::::;;::::;;::,,,,..::::,,::::..::::::::::::::,,,,::..
..::::::::::::::;;::::;;,,,,,,::::::::..:: ....::::::,,,,,,,,::..
....::::::::::::::::::,,::::::::...... ..::::::::::;;;;,,::....
..::::::::::::,,::,,::::::::::....:: ..::::::::;;;;;;;;,,::..
....::::::::::::::;;::::::..::..::::,,::,,::::;;;;;;;;;;,,::..
....::::::::::,,,,;;,,,,,,::::::::::,,::;;,,;;;;;;ii;;;;::::
....::::::,,,,,,;;;;;;;;;;iiiiiiii;;;;;;ii;;iiiiii;;;;::::
....::::,,;;;;;;;;iiiittjjjjLLLLffffjjiiiiiiiiii;;;;::::..
....::,,;;;;;;,,iittttjjjjffLLffjjttiiiiiiiiii;;,,::..
....::,,;;;;iiiiiittttjjjjjjjjjjttiiiiiiiiii;;::::..
::::;;iiiiiiiiiiiittttttttttttiiiiiiii;;,,::..
....::,,;;;;iiii;;;;iiii;;;;iiii;;;;;;,,::::..
..::::,,;;;;;;,,,,;;;;,,,,;;;;,,,,::::....
....::::::::::::::::::::::::::::::....
....::::::::::::::::::::........
..................


Through me the way is to the city dolent;
Through me the way is to eternal dole;
Through me the way among the people lost.

Justice incited my sublime Creator;
Created me divine Omnipotence,
The highest Wisdom and the primal Love.

Before me there were no created things,
Only eterne, and I eternal last.
All hope abandon, ye who enter in!

*
*
***

Per me si va ne la città dolente,
per me si va ne l'etterno dolore,
per me si va tra la perduta gente.

Giustizia mosse il mio alto fattore:
fecemi la divina podestate,
la somma sapienza e 'l primo amore.

Dinanzi a me non fuor cose create
se non etterne, e io etterno duro.
Lasciate ogne speranza, voi ch'intrate".

*
*
***

Por mi se va a la ciudad doliente,
por mi se va al eterno dolor,
por mi se va con la perdida gente.

La Justicia movio a mi supremo Autor;
me hizo la divina potestad,
la suma sabiduría y el amor primero.

Antes de mí no hubo nada creado,
a excepción de los seres eternos, y yo duro eternamente.
Dejad toda esperanza los que entráis.

*
*
***

Ahora me he convertido en la muerte, destructora de mundos.
Soy la Muerte que se lleva todo, la fuente de las cosas que vendran.

Soy el espectro de aquellos que dominan los pueblos, el arte politico de los conquistadores, el silencio de los secretos, el conocimiento de los conocedores.

Soy yo quien recalienta, retiene, o deja ir la lluvia; yo soy la inmortabilidad y la muerte; soy yo quien soy, el ser y el no ser.

D1rkAvenger

|_|0|_|
|_|_|0|
|0|0|0|

We were young full of hopes. Now, we're old full of remorse...

Saludos a todos

Hola a todos, esta es mi primer entrada en el mundo de los blogs, aunque sin duda llevo años escribiendo en listas de discusión sobre linux y bases de datos, pues ahora me doy cuenta que es muy importante el publicar mucha información que tengo guardada aqui y por alla y que sin duda a mas de alguno le servira.

Todos sus comentarios y aportes a esta pagina son bien recibidos y nos vemos pronto por aqui.

Bahia desde el balcon...

Bahia desde el balcon...
Ixtapa Zihuatanejo