<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
	xmlns:media="http://search.yahoo.com/mrss/"
>

<channel>
	<title>Con G de GNU &#187; Guias y manuales</title>
	<atom:link href="http://www.congdegnu.es/category/guias-manuales/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.congdegnu.es</link>
	<description>aptitude install freedom</description>
	<lastBuildDate>Mon, 21 Jun 2010 16:53:23 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<!-- podcast_generator="podPress/8.8" -->
		<copyright>&#xA9; </copyright>
		<managingEditor>congdegnu@gmail.com ()</managingEditor>
		<webMaster>congdegnu@gmail.com()</webMaster>
		<category></category>
		<itunes:keywords></itunes:keywords>
		<itunes:subtitle></itunes:subtitle>
		<itunes:summary>aptitude install freedom</itunes:summary>
		<itunes:author></itunes:author>
		<itunes:category text="Society &amp; Culture"/>
		<itunes:owner>
			<itunes:name></itunes:name>
			<itunes:email>congdegnu@gmail.com</itunes:email>
		</itunes:owner>
		<itunes:block>No</itunes:block>
		<itunes:explicit>no</itunes:explicit>
		<itunes:image href="http://www.congdegnu.es/wp-content/plugins/podpress/images/powered_by_podpress_large.jpg" />
		<image>
			<url>http://www.congdegnu.es/wp-content/plugins/podpress/images/powered_by_podpress.jpg</url>
			<title>Con G de GNU</title>
			<link>http://www.congdegnu.es</link>
			<width>144</width>
			<height>144</height>
		</image>
		<item>
		<title>Monta tu servidor ssh rápidamente</title>
		<link>http://www.congdegnu.es/2010/06/21/monta-tu-servidor-ssh-rapidamente/</link>
		<comments>http://www.congdegnu.es/2010/06/21/monta-tu-servidor-ssh-rapidamente/#comments</comments>
		<pubDate>Mon, 21 Jun 2010 16:49:05 +0000</pubDate>
		<dc:creator>Maxpowel</dc:creator>
				<category><![CDATA[Guias y manuales]]></category>
		<category><![CDATA[clonezilla]]></category>
		<category><![CDATA[drbl]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://www.congdegnu.es/?p=1175</guid>
		<description><![CDATA[Buenas!
No es un espejismo no, estoy escribiendo algo en el blog! Bromas a parte, en post donde comento cómo usar clonezilla una persona pidió un manual de cómo montar un servidor ssh. Es tan sumamente sencillo que me daría rabia si esa persona no es capaz de automatizar todo el sistema de clonado de imágenes [...]]]></description>
			<content:encoded><![CDATA[<p>Buenas!<br />
No es un espejismo no, estoy escribiendo algo en el blog! Bromas a parte, en post donde comento <a href="http://www.congdegnu.es/2009/02/20/clonando-con-drbl-y-clonezilla-usando-multicast/">cómo usar clonezilla</a> una persona pidió un manual de cómo montar un servidor ssh. Es tan sumamente sencillo que me daría rabia si esa persona no es capaz de automatizar todo el sistema de clonado de imágenes por algo tan nimio como es el preparar el servidor ssh.</p>
<p>Comienzo explicando los conceptos básicos sobre ssh en Linux.</p>
<h1><span id="more-1175"></span><strong>Descripción de SSH</strong></h1>
<p>Por decirlo de manera sencilla, SSH nos permite conectarnos a una máquina remota de manera segura. Además de cifrar el canal de comunicación es obligatoria la autenticación.<br />
Para esto hay dos maneras, una es mediante usuario y contraseña y la otra es mediante el uso de claves públicas y privadas.</p>
<p>Cuando queremos entrar con un usuario y contraseña usamos los usuarios del sistema. A nosotros nos da igual donde estén esos usuarios creados (archivos /etc/passwd, servidor LDAP&#8230;) de eso se encargará el sistema.</p>
<p>Cuando nos conectamos por SSH al servidor entramos con los permisos del usuario que hemos usado. Por ejemplo, si yo entro con el usuario &#8220;alvaro&#8221; (un usuario normal) mi home será /home/alvaro y sólo tendré permiso de escritura a ese directorio. Otro usuario como es root tiene acceso a todo el sistema. Por seguridad en muchos servidores el usuario root esté deshabilitado.</p>
<p>En resumidas cuentas, a efectos prácticos SSH es <strong>igual</strong> que usar el terminal de tu ordenador, pero esas órdenes se ejecutan en el servidor remoto.<br />
Veamos algun ejemplo.<br />
<a href="http://www.congdegnu.es/wp-content/uploads/2010/06/sshDesc.png"><img class="aligncenter size-full wp-image-1178" src="http://www.congdegnu.es/wp-content/uploads/2010/06/sshDesc.png" alt="Conexion ssh" /></a><br />
Al pricipio estoy en mi ordenador. Ejecutando el comando &#8220;whoami&#8221; vemos que el usuario soy y mi estoy en mi máquina. Nos podemos dar cuenta porque pone &#8220;alvaro@flanders&#8221; (flanders es el hostname de mi ordenador).<br />
Despues ejecutamos el comando ssh usuario@servidor. Nos conectaremos con el usuario &#8220;usuario&#8221; al servidor &#8220;servidor&#8221; y luego nos pregunta por la contraseña. Si introducimos la contraseña correcta entramos al servidor. Nos muestra un texto de bienvenida y vemos que ahora no pone &#8220;alvaro@flanders&#8221; sino que pone &#8220;server&#8221; (server es el hostname del servidor, muy original sí). También ejecutando el comando whoami vemos que el usuario ahora es root y no alvaro. Ahora todo lo que escriba en ese termina se ejecutará en el servidor con los permisos de root.</p>
<p>Ahora que ya sabemos un poco de qué va esto del SSH vamos a instalarlo</p>
<h1><strong>Instalación de SSH</strong></h1>
<p>Tan sencillo como instalar el paquete openssh-server<br />
<code>sudo aptitude install openssh-server</code></p>
<p><a href="http://www.congdegnu.es/wp-content/uploads/2010/06/sshDesc2.png"><img class="aligncenter size-full wp-image-1182" src="http://www.congdegnu.es/wp-content/uploads/2010/06/sshDesc2.png" alt="" /></a></p>
<p>Iniciamos el servicio ssh</p>
<p>/etc/init.d/ssh start</p>
<p>Y ya podemos conectarnos al servidor</p>
<p><a href="http://www.congdegnu.es/wp-content/uploads/2010/06/sshDesc3.png"><img class="aligncenter size-full wp-image-1184" src="http://www.congdegnu.es/wp-content/uploads/2010/06/sshDesc3.png" alt="" /></a>Hacemos la prueba y vemos que me he contectado sin problema. Si tienes más ordenadores en tu red local prueba a conectarte desde uno de ellos.<br />
Recuerda que los datos que debes usar son un usuario del servidor y el hostname (o dirección ip del servidor, por ejemplo</p>
<p>ssh usuario@192.168.1.110</p>
<p>Suponiendo que el usuario &#8220;usuario&#8221; existe en el servidor y que la dirección ip (local) de tu servidor es &#8220;192.168.1.110&#8243;.</p>
<p>Y ya está! Ha sido fácil verdad?</p>
<h1>Notas sobre ssh-server y clonezilla</h1>
<p>Como dije al principio, escribo este artículo a partir de <a href="../2009/02/20/clonando-con-drbl-y-clonezilla-usando-multicast/">este</a> y los datos por los que te pregunta son los siguientes:</p>
<p><div id="attachment_674" class="wp-caption aligncenter" style="width: 810px"><a href="http://www.congdegnu.es/wp-content/uploads/2009/02/retardo5.png"><img class="size-full wp-image-674" src="http://www.congdegnu.es/wp-content/uploads/2009/02/retardo5.png" alt="" width="800" height="600" /></a><p class="wp-caption-text">Esto la dirección de tu servidor SSH. Donde has instalado el SSH.</p></div></p>
<p style="text-align: center"><a href="http://www.congdegnu.es/wp-content/uploads/2009/02/retardo9.png"></a></p>
<p><div id="attachment_675" class="wp-caption aligncenter" style="width: 810px"><a href="http://www.congdegnu.es/wp-content/uploads/2009/02/retardo6.png"><img class="size-full wp-image-675" src="http://www.congdegnu.es/wp-content/uploads/2009/02/retardo6.png" alt="" width="800" height="600" /></a><p class="wp-caption-text">El usuario del servidor que usarás para conectarte a él (para almacenar la imagen del disco duro)</p></div></p>
<p><div id="attachment_677" class="wp-caption aligncenter" style="width: 810px"><a href="http://www.congdegnu.es/wp-content/uploads/2009/02/retardo8.png"><img class="size-full wp-image-677" src="http://www.congdegnu.es/wp-content/uploads/2009/02/retardo8.png" alt="" width="800" height="600" /></a><p class="wp-caption-text">El directorio del servidor donde se guardará la imagen del disco duro. Recuerda que el usuario que elegiste antes tiene que tener permisos de escritura en ese directorio del servidor.</p></div></p>
<p style="text-align: center">
<p style="text-align: left">Espero que se hayan podido solucionar todas las dudas respecto a este tema. Si no, puedes preguntar por lo que no te ha quedado claro por supuesto.</p>
<p style="text-align: left">
<p style="text-align: left">Un saludo!!</p>


<p>Entradas relacionadas:<ol><li><a href='http://www.congdegnu.es/2009/02/20/clonando-con-drbl-y-clonezilla-usando-multicast/' rel='bookmark' title='Permanent Link: Clonando con DRBL y Clonezilla (usando multicast!)'>Clonando con DRBL y Clonezilla (usando multicast!)</a> <small> Saludos, antes de nada disculparme por la tardanza y...</small></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.congdegnu.es/2010/06/21/monta-tu-servidor-ssh-rapidamente/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Oh no! bad geometry: block count exceeds size of device</title>
		<link>http://www.congdegnu.es/2009/11/29/oh-no-bad-geometry-block-count-exceeds-size-of-device/</link>
		<comments>http://www.congdegnu.es/2009/11/29/oh-no-bad-geometry-block-count-exceeds-size-of-device/#comments</comments>
		<pubDate>Sun, 29 Nov 2009 14:07:43 +0000</pubDate>
		<dc:creator>Maxpowel</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[Guias y manuales]]></category>
		<category><![CDATA[bad geometry]]></category>
		<category><![CDATA[block count exceeds]]></category>
		<category><![CDATA[debugfs]]></category>
		<category><![CDATA[e2fsprogs]]></category>
		<category><![CDATA[rdump]]></category>

		<guid isPermaLink="false">http://www.congdegnu.es/?p=1128</guid>
		<description><![CDATA[A quien no le ha salido este error?? Nadie?? Bueno, a alguien seguro que sí. La verdad es que es un error muy chungo que te puede hacer perder toda una partición a pesar de saber que los datos están intactos.
Primero, ¿Qué quiere decir este fallo? Pues básicamente que la partición dice que tiene un [...]]]></description>
			<content:encoded><![CDATA[<p>A quien no le ha salido este error?? Nadie?? Bueno, a alguien seguro que sí. La verdad es que es un error muy chungo que te puede hacer perder toda una partición a pesar de saber que los datos están intactos.</p>
<p>Primero, ¿Qué quiere decir este fallo? Pues básicamente que la partición dice que tiene un tamaño superior del que realmente tiene y en cuando intentamos montar esa partición linux detecta un problema y dice &#8220;soo, que aquí algo no cuadra&#8221;.<br />
Bueno, más concretamente dice</p>
<p>mount: wrong fs type, bad option, bad superblock on /dev/sda5,<br />
missing codepage or helper program, or other error<br />
In some cases useful info is found in syslog &#8211; try<br />
dmesg | tail  or so</p>
<p><span id="more-1128"></span>Este error, si te ha ocurrido, lo más probable es que haya sido provocado al redimensionar</p>
<p>o mover una partición y la tarea no se realizó con éxito. Leyendo por internet he visto que<br />
bastante gente le ha pasado usando como sistema de ficheros ext4 pero en ningún lado daban<br />
una solución diferente de &#8220;recupera un backup&#8221;.<br />
Para una empresa es imprescindible tener backups de todo pues es la manera más rápida y segura<br />
de recuperar información perdida pero no todos tenemos ni los conocimientos ni recursos para tener<br />
backups de todo.<br />
Si no tienes backup de esa partición te voy a ayudar a recuperar los datos.</p>
<p>Como dije antes, la partición no se puede montar por incoherencias en el sistema de ficheros pero<br />
todos los archivos están ahí. Vamos usar una grandiosa herramienta para sistemas de ficheros ext<br />
llamada<em> <a title="e2fsprogs" href="http://e2fsprogs.sourceforge.net/" target="_blank">e2fsprogs</a></em><br />
Repito, esta herramienta es muy muy potente aunque nosotros nos vamos a limitar a usarla para<br />
bucear en el sistema de ficheros corrupto. No hace falta instalar nada, todos los linuxes lo traen de<br />
serie (he dicho alguna vez lo maravilloso que es linux?). En mi caso se me rompió la partición home<br />
con bastantes cosas que me costaría recomponer (si hubiera sido la del sistema probablemente me<br />
hubiera limitado a volver a crear la partición y reinstalar el sistema) y use una maravillosa distribución<br />
live llamada <a title="System Rescue CD" href="http://www.sysresccd.org/Main_Page" target="_blank">systemrescuecd</a> que desde mi punto de vista es una herramienta imprescindible a tener en<br />
el cajon.</p>
<p>Una vez el sistema arrancado entramos en un terminal como administrador ejecutamos<br />
<em>debugfs</em> /dev/sda5 (/dev/sda5 era mi partición pero ahí tiene que poner la tuya).<br />
Si ha ido bien la cosa nos habrá aparecido un prompt para meter comandos. Puedes probar con ls para<br />
listar y ver está listando bien los directorios. En mi caso quería copiar todo el contenido del directorio<br />
&#8220;alvaro&#8221; así que usé el siguiente comando:</p>
<p><em>rdump alvaro /saca/alvaro</em></p>
<p>Explico el comando:<br />
rdump (dentro del prompt de debugfs) hace un volcado recursivo. Si solo usamos dump lo que haría es volcar un solo<br />
archivo pero si quieres copiar un directorio hay que usar rdump<br />
alvaro es la carpeta de la particion corrupta (la que aparece haciendo ls dentro de debugfs)<br />
/saca/alvaro es el directorio a donde se van a volcar los datos. En mi caso monté un disco duro de 500 gigas. Recuerda tener<br />
espacio suficiente libre en el destino!.</p>
<p>Después de un ratito (dependiendo de lo que tenga que copiar) verás que ha terminado. Comprueba que te ha recuperado todo.<br />
Yo hice un du -h /saca/alvaro para ver que ocupaba los 28GB que ocupaba mi home. Navega un poco por los directorios recién<br />
copiados y si todo está correcto pues borras la partición (con gparted por ejemplo) la vuleves a crear y copias los archivos en esa<br />
partición. En mi caso como era el directorio home de mi usuario cambié el propietario (ya que era root) a alvaro con <em>chown -R alvaro</em>.<br />
Ahora al iniciar el sistema todo debería ir perfectamente.</p>
<p>Resumiendo:<br />
1 &#8211; debugfs particion<br />
2 &#8211; rdump directorioDeParticion directorioDestino</p>
<p>Y en directorioDestino tendremos los archivos a salvo.</p>
<p>Vemos que algo en principio tan catastrófico se soluciona tan fácil. Que cosas tiene la vida.<br />
Un saludo!</p>


<p>Entradas relacionadas.</p>]]></content:encoded>
			<wfw:commentRss>http://www.congdegnu.es/2009/11/29/oh-no-bad-geometry-block-count-exceeds-size-of-device/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Conoce SQL &#8211; Lenguaje procedimental 4 &#8211; Triggers</title>
		<link>http://www.congdegnu.es/2009/05/12/conoce-sql-lenguaje-procedimental-4-triggers/</link>
		<comments>http://www.congdegnu.es/2009/05/12/conoce-sql-lenguaje-procedimental-4-triggers/#comments</comments>
		<pubDate>Tue, 12 May 2009 09:20:26 +0000</pubDate>
		<dc:creator>Maxpowel</dc:creator>
				<category><![CDATA[Guias y manuales]]></category>
		<category><![CDATA[Humor]]></category>
		<category><![CDATA[after]]></category>
		<category><![CDATA[before]]></category>
		<category><![CDATA[check]]></category>
		<category><![CDATA[disparadores]]></category>
		<category><![CDATA[for each row]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[on]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[trigger]]></category>
		<category><![CDATA[triggers]]></category>

		<guid isPermaLink="false">http://www.congdegnu.es/?p=969</guid>
		<description><![CDATA[También llamados disparadores, lo que hace un trigger es estar alerta hasta que sucede algo y saltan. Por ejemplo un foreign key se podría interpretar como un trigger que comprueba que existe un valor en otra tabla cada vez que insertarmos o actualizamos un dato de una tabla. O un UNIQUE podría ser un trigger [...]]]></description>
			<content:encoded><![CDATA[<p>También llamados disparadores, lo que hace un trigger es estar alerta hasta que sucede algo y saltan. Por ejemplo un foreign key se podría interpretar como un trigger que comprueba que existe un valor en otra tabla cada vez que insertarmos o actualizamos un dato de una tabla. O un UNIQUE podría ser un trigger que antes de insertar comprueba que no está ya insertado uno igual.</p>
<p>Básicamente un trigger está a la escucha de una tabla esperando que se haga un insert, update o delete sobre ella y actuar de una determinada manera. Usos que se le puede dar por ejemplo es para crear logs. Cada vez que un usuario inserte un comentario se añade a otra tabla &#8220;El usuario tal a insertado la foto cual&#8221; o cada vez que se modifique un perfil por ejemplo. También para validación avanzada de datos. Cuando se ejecuta un insert podemos tirarlo si no nos gusta (al igual que un update o un delete). En el capítulo de los checks mencióne esto no sé si te acuerdas. También podemos hacer una tabla de solo inserción (cancelando todos los deletes)&#8230; infinidad de cosas.</p>
<p>También podemos elegir si el trigger actua antes o despues de realizarse la consulta. Depende de la finalidad nos interesa una cosa u otra. Por ejemplo si lo que queremos es validar datos el trigger se tiene que ejecutar antes para así evitar que se lleguen a insertar los datos. Pero si lo que queremos es por ejemplo crear un contador de usuarios, el trigger tiene que saltar después de realizarse la consulta para que solo se ejecute cuando la consulta se ha realizado correctamente y no cuando se ha intentado insertar un usuario y no se ha podido por el motivo que sea, con lo que el contador mostraría información incorrecta.</p>
<p>Como en el capítulo anterior,  usaré ejemplos de Cutrenti (qué bueno que sea software libre!)<br />
<span id="more-969"></span></p>
<p>Comenzaremos con un trigger que copia datos borrados a otra tabla. Este trigger lo hice cuando implementé el borrado de comentarios en respuesta a posibles vulnerabilidades. El poder borrar es algo con lo que hay que tener mucho cuidado ya que hay que evitar que alguien pueda borrar algo que no es suyo. Pero como siempre (por muy seguro que esté) dejo la posibildad del fallo decidí hacer una especie de &#8220;backup&#8221; de los comentarios así si alguien encontraba un bug (cosa que no ha sucedido jeje) y se dedicaba a borrar todos los comentarios no tenía mas que restaurarlos de la tabla. El trigger en cuestión es este</p>
<blockquote><p>CREATE TRIGGER almacenar_comentarios<br />
AFTER DELETE ON tablones<br />
FOR EACH ROW<br />
BEGIN<br />
INSERT INTO tablones_log (id_usuario,n_mensaje,id_autor,contenido,n_mensaje_respuesta,fecha_tablon,id_multimedia) values (old.id_usuario,old.n_mensaje,old.id_autor,old.contenido,old.n_mensaje_respuesta,old.fecha_tablon,old.id_multimedia);<br />
END</p></blockquote>
<p>La primera línea define el trigger con su nombre. Después indicamos cuando queremos que el trigger salte si antes de la ejecución de la consulta o después. En este caso quería que se ejecutase después ya que solo me interesaba copiar los comentarios que borraban realmente. Como queremos controla la acción de borrado ponemos DELETE y la tabla a la que escucha el trigger es tablones (ON tablones). En inglés tiene bastante sentido que traducido seria &#8220;DESPUES de BORRAR EN tablones&#8221;. Es lo bueno de estos lenguajes de cuarta generación.</p>
<p>Y después se pone FOR EACH ROW y se abre código y ale a escribir lo que hace el trigger. Las posibilidades del trigger nos permite AFTER o BEFORE (antes o después) y DELETE y/o UPDATE y/o DELETE. Es conveniente solo escuchar aquello que nos interesa, por ejemplo en este trigger sería malo poner que escuchara al insertar y actualizar ya que no haría nada pero mysql ha tenido que lanzar un proceso para ejecutar el trigger y siempre que podamos evitar molestar a mysql la base de datos irá más rápida. Sí, eso tarda 0,0001 milisegundos pero si multiplicas eso por cada fila y por cada consulta haz cuentas&#8230;</p>
<p>Ahora un ejemplo de como tirar una consulta. Cuando un usuario se registra en Cutrenti, se inserta en una tabla temporal hasta que es validado. El problema viene si quiero controlar que no se repitan emails. Tengo un UNIQUE en la tabla usuarios pero como primero se insertan en la tabla usuarios_temporales daría el error cuando se mueve el usuario de la tabla temporal a la real. Eso sería realmente molesto para el usuario ya que de repente en el paso final le dice que su correo ya está registrado. En ese momento saltaría el trigger del usuario AFTER TOCAR HUEVOS que consiste en describir la página con argumentos un tanto soeces del tipo INSERT INTO descripciones_pagina (descripcion) VALUES (&#8216;mierda pagina&#8217;) , (&#8216;a este le dieron el titulo en la tombola);.</p>
<p>Para evitar esa situación uso un trigger. Como has adivinado este trigger se debería ejecutar antes de insertar el usuario temporal. El código es este:</p>
<blockquote><p>CREATE TRIGGER comprobar_email_temporal<br />
BEFORE INSERT ON usuarios_temporales<br />
FOR EACH ROW<br />
BEGIN<br />
DECLARE existe int;<br />
SET existe = (select 1 from usuarios WHERE email=new.email);</p>
<p>IF existe IS NOT null THEN<br />
SET new.hash=null;<br />
END IF;<br />
END</p></blockquote>
<p>Es bien sencillote. Cada vez que se hace insert ejecutamos una consulta donde buscamos el email en la tabla de usuarios reales y si ya existe hacemos una chapucilla para que falle la consulta. Esta chapucilla es poner el hash de validación (el código ese largote) a nulo y como ese campo tiene como restricción NOT NULL la consulta fallará. No hay otra manera en mysql (es la opción que recomiendan en la página de mysql) pero aquí lo ideal sería usar una excepción y ala que alguien se encarge de capturarla y si no se tira la consulta. He de decir que oracle en este aspecto esta muy muy avanzado y es una pena que mysql esté tan verde en ese tema porque el manejo de excepciones es muy interesante.</p>
<p>Entonces la solución para tirar una consulta es coger un campo (lo más fácil es coger la primary key) y ponerle un valor inválido,  por ejemplo nulo en caso de primary key (que lleva implícito el NOT NULL).</p>
<p>Pero, ¿Como hago para cambiar los valores de la consulta?</p>
<p>Has visto que en he hecho uso de unas tablas llamadas old y new. Esas tablas no las he creado yo, son unas temporales que se crean en los triggers para permitirnos hacer algo útil con los mismos.</p>
<p>La tabla new contiene los datos nuevos y la old los viejos (vaya, que listo soy). Me explico.<br />
En un insert no hay datos viejos asi que todos los campos de la tabla old son nulos. Pero en la tabla new tenemos todos los datos que se quieren insertar.</p>
<p>En un delete no hay datos nuevos (porque se borran) asi que new es nulo pero si hay datos viejos (los que hay y si quieren borrar), entonces en la tabla old están los datos actuales de la tabl.</p>
<p>En un update estan en la tabla new los datos nuevos que vamos a meter y en old los datos que van a ser sobreescritos.</p>
<p>Espero haberme explicado bien.</p>
<p>Con los trigger es muy común que las tablas muten. Por ejemplo, si es un trigger de tipo BEFORE INSERT no podemos hacer ni select, ni update ni delete a esa misma tabla porque está bloqueada. He visto casos en los que sí deja hacer select pero eso será por cuestiones internas de mysql que igual hace el select antes de bloquear la tabla o alguna movida interna. Pero vamos, que es imprevisble y no podemos contar con eso porque también he visto que en un principio el trigger no fallaba pero metiendo más datos daba problema de mutación de tabla. Repito, es imprevisible cuando una tabla puede mutar si leemos de ella mientras escribimos (escribir también es borrar) así que mejor no jugar con eso. Si intuyes que puede haber mutación, busca otra manera aunque en principio no te de fallo. Con el tiempo verás con antelación si una tabla puede mutar o no pero hay veces (en trigger complejos) en los que no te das cuenta hasta que peta.</p>
<p>Sabiendo esto ya puedes hacer triggers majos pero no te líes la manta a la cabeza y empieces a hacer triggers como un loco para validar cualquier chorrada, recuerda que consume ciclos de CPU y que por cada fila (FOR EACH ROW) se ejecuta el trigger. Y vamos, ni se te ocurra hacer (ahora que ya lo conoces) validaciones de trigger en el script PHP no solo en eficiencia sino sobretodo por la integridad de los datos ya que siempre que tenemos que hacer algo mano se nos puede escapar algo.</p>
<p>Y como prometí, la emulación de la restricción CHECK mediante trigger. Creo recordar que teníamos una tabla tal que así (me permito añadir el not null para que nos salga el truquillo)</p>
<blockquote><p>CREATE TABLE paquetes2 (<br />
descripcion varchar(255) NOT NULL,<br />
entregado char(2),<br />
CONSTRAINT paquetes_entregado_ck CHECK (entregado=’si’ or entregado=’no’)<br />
)</p></blockquote>
<p>con la restricción que solo nos deja poner &#8220;si&#8221; o &#8220;no&#8221; en la columna entregado. El trigger podría ser este.</p>
<blockquote><p>CREATE TRIGGER paquetes_entregado_si_no_insert<br />
BEFORE INSERT ON paquetes2<br />
FOR EACH ROW<br />
BEGIN<br />
IF new.entregado&lt;&gt; &#8217;si&#8217; AND new.entregado&lt;&gt; &#8216;no&#8217;<br />
THEN<br />
SET new.codigo= NULL ;<br />
END IF;<br />
END</p></blockquote>
<p>y también sería recomendable insertar uno igual pero con BEFORE UPDATE para evitar cualquier posibilidad de datos inválidos. Recuerdo que el poner &lt;&gt; es lo mismo que != solo que &lt;&gt; es SQL estándar y lo otro no, aunque funciona igual.</p>
<p>Y ya está, ahora practicar y practicar!</p>


<p>Entradas relacionadas:<ol><li><a href='http://www.congdegnu.es/2009/05/07/conoce-sql-lenguaje-procedimental-1-estructura-y-sintaxis/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 1 &#8211; Estructura y sintaxis'>Conoce SQL &#8211; Lenguaje procedimental 1 &#8211; Estructura y sintaxis</a> <small>SQL es un gran lenguaje pero también tiene limitaciones. Pero...</small></li><li><a href='http://www.congdegnu.es/2009/05/08/conoce-sql-lenguaje-procedimental-2-funciones/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 2 &#8211; Funciones'>Conoce SQL &#8211; Lenguaje procedimental 2 &#8211; Funciones</a> <small>El concepto de función de el lenguaje procedimental de  mysql...</small></li><li><a href='http://www.congdegnu.es/2009/05/11/conoce-sql-lenguaje-procedimental-3-procedimientos/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 3 &#8211; Procedimientos'>Conoce SQL &#8211; Lenguaje procedimental 3 &#8211; Procedimientos</a> <small>La definición sencilla de procedimiento es que es una función...</small></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.congdegnu.es/2009/05/12/conoce-sql-lenguaje-procedimental-4-triggers/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Conoce SQL &#8211; Lenguaje procedimental 3 &#8211; Procedimientos</title>
		<link>http://www.congdegnu.es/2009/05/11/conoce-sql-lenguaje-procedimental-3-procedimientos/</link>
		<comments>http://www.congdegnu.es/2009/05/11/conoce-sql-lenguaje-procedimental-3-procedimientos/#comments</comments>
		<pubDate>Mon, 11 May 2009 08:21:03 +0000</pubDate>
		<dc:creator>Maxpowel</dc:creator>
				<category><![CDATA[Guias y manuales]]></category>
		<category><![CDATA[cursor]]></category>
		<category><![CDATA[insert]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[procedimental]]></category>
		<category><![CDATA[procedimiento]]></category>
		<category><![CDATA[procedure]]></category>
		<category><![CDATA[select]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[update]]></category>

		<guid isPermaLink="false">http://www.congdegnu.es/?p=964</guid>
		<description><![CDATA[La definición sencilla de procedimiento es que es una función pero que no devuelve nada. Bueno,  realmente si se pueden obtener datos usando parámetros OUT pero vuelvo a recomendar no usarlos. El motivo no es que funcione mal sino que la idea de un procedimiento no es obtener datos, para eso usa una función o [...]]]></description>
			<content:encoded><![CDATA[<p>La definición sencilla de procedimiento es que es una función pero que no devuelve nada. Bueno,  realmente si se pueden obtener datos usando parámetros OUT pero vuelvo a recomendar no usarlos. El motivo no es que funcione mal sino que la idea de un procedimiento no es obtener datos, para eso usa una función o una vista.</p>
<p>El caso típico de un procedimiento es por ejemplo insertar un usuario. A la hora de insertar un usuario quizá necesitemos hacer alguna comprobación (algo más complejo que lo que nos pueda dar una restricción UNIQUE) o insertar filas en otras tablas , etc. Vamos a ponernos en situación y con un ejemplo real. En Cutrenti la inserción de usuarios la hace un procedimiento al que se le pasa el email, el nombre, los apellidos y la constraseña. Entonces cuando se inserta un usuario genera actividad de ese usuario (insertando una fila en ultimos cambios) y además se añanden los emoticonos predeterminados a la lista de emoticonos del usuario.</p>
<p>Como ves, estamos trasladando toda la lógica del registro del usuario a mysql en vez de hacerlo con php.</p>
<p><span id="more-964"></span></p>
<p>Primero definimos el procedimiento:</p>
<blockquote><p>CREATE  PROCEDURE insertar_usuario (in v_nombre varchar(25), in v_apellido1 varchar(25), in v_apellido2 varchar(25), in v_email varchar(25), in v_password varchar(25))</p></blockquote>
<p>Ya está, aquí no hace falta poner returns ni nada. Es sencillo y sin complicaciones. Ahora se inicia un bloque de código (con BEGIN) y se escribe lo que quieres que haga el procedimiento</p>
<blockquote><p>BEGIN<br />
INSERT INTO usuarios (nombre,apellido1,apellido2,email,md5_pass) VALUES (v_nombre,v_apellido1,v_apellido2,v_email,MD5(v_password));</p>
<p>INSERT INTO ultimos_cambios(id_usuario) values(LAST_INSERT_ID());</p>
<p>INSERT INTO usuarios_emoticonos (archivo,id_usuario) VALUES (&#8216;11c14bd1496afd0e21df115d25b68e96&#8242;,LAST_INSERT_ID());<br />
INSERT INTO usuarios_emoticonos (archivo,id_usuario) VALUES (&#8216;19bb8ebfe3c2f5ef3ffb9aa4a027900d&#8217;,LAST_INSERT_ID());<br />
INSERT INTO usuarios_emoticonos (archivo,id_usuario) VALUES<br />
END</p></blockquote>
<p>Simplemente lo que hemos hecho ha sido meter consultas INSERT dentro procedimiento. Primero inserta el usuario y si no se crea (por reesctricciones o cualquier cosa) tampoco se insertarán últimos cambios ni emoticonos (aquí solo hay dos, esque no iba a poner los 20 o así que son). No hay condiciones que controlen eso pero sí restricciones. Si el usuario no se ha podido insertar, LAST_INSERT_ID() devuelve el numero &#8216;0&#8242; que no coincide con el de ningún usuario entonces salta el foreign key diciendo &#8220;ey, que no hay usuario con el id &#8216;0&#8242;&#8221; y no se insertan. Aquí las restricciones nos han ayudado a hacer un procedimiento más sencillo.</p>
<p>Bien, este procedimiento es muy chorra así que vamos con un mas completito. Este procedimiento también es de Cutrenti y sirve para comentar fotos. Cuando se comenta una foto, además de insertar la foto hay que avisar de ese comentario a todos los usuarios etiquetados. Como has adivinado, aquí usamos un cursor también.</p>
<blockquote><p>CREATE  PROCEDURE comentar_foto (v_id_comentador INT, v_id_usuario_foto INT, v_n_foto INT, v_comentario VARCHAR(255), v_audio INT)<br />
BEGIN<br />
DECLARE ultimo INT;<br />
DECLARE v_id_aparicion int;<br />
DECLARE v_audio_fin int;<br />
DECLARE terminado INT DEFAULT 0;<br />
DECLARE c_apariciones CURSOR FOR SELECT id_aparicion FROM apariciones where id_usuario=v_id_usuario_foto and n_foto=v_n_foto and id_aparicion&lt;&gt;v_id_comentador;<br />
DECLARE CONTINUE HANDLER FOR SQLSTATE &#8216;02000&#8242; SET terminado = 1;</p>
<p>SET ultimo = (select n_comentario from comentarios WHERE id_usuario=v_id_usuario_foto and n_foto=v_n_foto ORDER BY n_comentario DESC LIMIT 1)+1;</p>
<p>SET v_audio_fin = v_audio;</p>
<p>IF v_audio_fin &lt; 0 THEN<br />
SET v_audio_fin=null;<br />
END IF;</p>
<p>IF ultimo IS null THEN<br />
SET ultimo=0;<br />
END IF;<br />
INSERT INTO comentarios (id_usuario,n_foto,id_comentador,comentario,n_comentario,id_multimedia) VALUES (v_id_usuario_foto,v_n_foto,v_id_comentador,v_comentario,ultimo,v_audio_fin);</p>
<p>OPEN c_apariciones;<br />
REPEAT<br />
FETCH c_apariciones into v_id_aparicion;<br />
IF terminado = 0 THEN<br />
UPDATE usuarios SET nuevos_comentarios=1 WHERE id_usuario=v_id_aparicion;<br />
INSERT INTO nuevos_comentarios (id_usuario,id_usuario_foto,n_foto) VALUES (v_id_aparicion,v_id_usuario_foto,v_n_foto);<br />
END IF;<br />
UNTIL terminado END REPEAT;</p>
<p>CLOSE c_apariciones;</p>
<p>END</p></blockquote>
<p>Primero obtenemos el último id para sumarle uno y así tener el nuevo id. No podemos usar AUTO INCREMENT porque la clave primaria está formada por varios elementos y por desgracia MySQL no lo permite. Después comprobamos si se ha insertado un audio. No comprobamos si el audio existe o no ya que la restricción foreign key lo hará por nosotros (si no existe, no deja que se cree). Después se inserta el comentario y por último se avisa a todos los usuarios etiquetados a los que llamo &#8220;apariciones&#8221;. Eso se hace un con cursor y un bucle. Este bucle sería el equivalente a un &#8220;do while&#8221;. La característica de ese bucle es que siempre se entra por lo menos una vez a diferencia de while donde sólo se entra si se cumple la condición (y puede que ni se entre al bucle).</p>
<p>Ese cursor lo que hace es actualizar el estado de cada usuario que aparece en la foto e insertar el tipo de actividad. Esto se repetirá mientras haya &#8220;apariciones&#8221;.</p>
<p>En este procedimiento hemos usado INSERT, SELECT y UPDATE con cursor de regalo. Se podría decir que es un ejemplo bastante completito. Luego ya te puedes líar aninando cursores y todo lo que se te ocurra.</p>
<p>Creo que con estos ejemplos queda más o menos claro el uso que se le puede dar a un procedimiento y esque no es más que una función que podamos hacer en PHP pero beneficiándonos de las ventajas que nos da el gestor de bases de datos, como por ejemplo la independencia que tenemos al estar insertado en la base de datos y poder usarlo desde cualquier programa.</p>
<p>Y por último, para usar un procedimiento la consulta es la siguiente:</p>
<blockquote><p>call nombre_procedimiento (parametro1,parametro2)</p></blockquote>
<p>Como último consejo, es recomendable que este tipo de funciones se hagan en el sistema gestor de bases de datos y no en la propia aplicación. Lo siguiente ya son los triggers, muy interesantes no te lo puedes perder!</p>


<p>Entradas relacionadas:<ol><li><a href='http://www.congdegnu.es/2009/05/07/conoce-sql-lenguaje-procedimental-1-estructura-y-sintaxis/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 1 &#8211; Estructura y sintaxis'>Conoce SQL &#8211; Lenguaje procedimental 1 &#8211; Estructura y sintaxis</a> <small>SQL es un gran lenguaje pero también tiene limitaciones. Pero...</small></li><li><a href='http://www.congdegnu.es/2009/05/12/conoce-sql-lenguaje-procedimental-4-triggers/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 4 &#8211; Triggers'>Conoce SQL &#8211; Lenguaje procedimental 4 &#8211; Triggers</a> <small>También llamados disparadores, lo que hace un trigger es estar...</small></li><li><a href='http://www.congdegnu.es/2009/05/08/conoce-sql-lenguaje-procedimental-2-funciones/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 2 &#8211; Funciones'>Conoce SQL &#8211; Lenguaje procedimental 2 &#8211; Funciones</a> <small>El concepto de función de el lenguaje procedimental de  mysql...</small></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.congdegnu.es/2009/05/11/conoce-sql-lenguaje-procedimental-3-procedimientos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Conoce SQL &#8211; Lenguaje procedimental 2 &#8211; Funciones</title>
		<link>http://www.congdegnu.es/2009/05/08/conoce-sql-lenguaje-procedimental-2-funciones/</link>
		<comments>http://www.congdegnu.es/2009/05/08/conoce-sql-lenguaje-procedimental-2-funciones/#comments</comments>
		<pubDate>Fri, 08 May 2009 12:30:22 +0000</pubDate>
		<dc:creator>Maxpowel</dc:creator>
				<category><![CDATA[Guias y manuales]]></category>
		<category><![CDATA[begin]]></category>
		<category><![CDATA[funcion]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[procedimental]]></category>
		<category><![CDATA[return]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.congdegnu.es/?p=958</guid>
		<description><![CDATA[El concepto de función de el lenguaje procedimental de  mysql es el mismo que en cualquier otro lenguaje, se le dan unos datos y devuelve otros.
En este lenguaje existen varibles IN, variables OUT y variables INOUT. Las variables IN son aquellas que se pasan como parametros y no se pueden editar y las OUT pues [...]]]></description>
			<content:encoded><![CDATA[<p>El concepto de función de el lenguaje procedimental de  mysql es el mismo que en cualquier otro lenguaje, se le dan unos datos y devuelve otros.</p>
<p>En este lenguaje existen varibles IN, variables OUT y variables INOUT. Las variables IN son aquellas que se pasan como parametros y no se pueden editar y las OUT pues que sí se pueden editar. En el caso de las funciones, los parámetros son de tipo IN de manera predeterminada. Recomiendo encarecidamente no usar variables OUT o INOUT, en mi opinión está &#8220;feo&#8221; editar las variables que te pasan a la función.</p>
<p>Lo que devuelve una función tiene que ser compatible con SQL. Me refiero a que por ejemplo no puedes devolver un valor booleano porque en SQL no existe ese tipo de datos.</p>
<p>Nuestras funciones las podemos usar de la misma manera que las funciones de mysql, veamos algún ejemplo.</p>
<p><span id="more-958"></span></p>
<p>La sintaxis es la siguiente</p>
<blockquote><p>CREATE FUNCTION funcion (var1 INT, var2 VARCHAR(20))<br />
RETURNS INT<br />
BEGIN<br />
&#8211;HACER algo<br />
return var1;<br />
END</p></blockquote>
<p>Las dos primeras líneas son el prototipo de la función, los parámetros que se le pasan y el tipo de dato que devuelve (en ese caso int pero puede ser varchar, char&#8230;). Dentro se pueden meter cursores, bucles y todo lo que quieras.</p>
<p>Para ejecutar nuestra función simplemente hacer:</p>
<blockquote><p>SELECT funcion(5,&#8217;hola&#8217;)</p></blockquote>
<p>Eso daría como resultado 5, ya que devuelve la variable que le pasamos (sí, una función totalmente estúpida). Ahora suponemos que tenemos esta función:</p>
<blockquote><p>CREATE FUNCTION doblar (var1 INT)<br />
RETURNS INT<br />
BEGIN<br />
SET var1=var1*2;<br />
return var1;<br />
END</p></blockquote>
<p>Podemos hacer esta consulta:</p>
<blockquote><p>SELECT doblar(precio), precio FROM articulos;</p></blockquote>
<p>Suponiendo que tenemos una tabla articulos con una columna llamada precio, esto nos mostraría el precio multiplicado por 2 y el precio normal.</p>
<p>Esto de las funciones esta bien pero para mysql no tienen mucho uso ya que NO se pueden devolver conjuntos de datos. Esto quiere decir que no podemos devolver el resultado de una consulta filtrada por ejemplo, algo que sería bastante interesante.</p>
<p>Termino diciendo que yo no uso nunca funciones. Simplemente porque no las encuentro utlilidad pero cada uno es cada uno, igual a ti te gustan.</p>


<p>Entradas relacionadas:<ol><li><a href='http://www.congdegnu.es/2009/05/07/conoce-sql-lenguaje-procedimental-1-estructura-y-sintaxis/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 1 &#8211; Estructura y sintaxis'>Conoce SQL &#8211; Lenguaje procedimental 1 &#8211; Estructura y sintaxis</a> <small>SQL es un gran lenguaje pero también tiene limitaciones. Pero...</small></li><li><a href='http://www.congdegnu.es/2009/05/11/conoce-sql-lenguaje-procedimental-3-procedimientos/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 3 &#8211; Procedimientos'>Conoce SQL &#8211; Lenguaje procedimental 3 &#8211; Procedimientos</a> <small>La definición sencilla de procedimiento es que es una función...</small></li><li><a href='http://www.congdegnu.es/2009/05/12/conoce-sql-lenguaje-procedimental-4-triggers/' rel='bookmark' title='Permanent Link: Conoce SQL &#8211; Lenguaje procedimental 4 &#8211; Triggers'>Conoce SQL &#8211; Lenguaje procedimental 4 &#8211; Triggers</a> <small>También llamados disparadores, lo que hace un trigger es estar...</small></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.congdegnu.es/2009/05/08/conoce-sql-lenguaje-procedimental-2-funciones/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
