Wordpress 2.6 incluye Google Gears para trabajar offline
BBDD, Javascript, Joomla, Wordpress
Leyendo anieto2k me entero que en la versión 2.6 de Wordpress se incluirá la tecnología Google Gears para trabajar offline, de esta manera se podrá seguir ecribiendo artículos aunque estemos en el campo sin conexión a internet, y después, en cuanto el navegador detecte una conexión, se sincronizará con la web y publicará todo el contenido escrito, un gran acierto
Cada vez se hace más potente la programación web y las posibilidades se hacen infinitas.
Google Gears es una implementación de Google para almacenar datos en el cliente y aún no esta muy extendido su uso, pero en el futuro standard HTML 5 esta prevista la inclusión de una BBDD en el navegador para facilitar la labor al programador y hacer las aplicaciones más dinamicas.
Ahora la pregunta para mí es: ¿Para cuando una cosa así en Joomla? , espero que no tarde mucho en desarrollarse.
Otra de las nuevas características incluidas en MySQL, además de los procedimientos almacenados, son los triggers, que traducido sería algo así como disparadores, son oyentes, que se mantienen a la escucha de los eventos que puedan producirse en una tabla (insert , update y delete) y ejecutan un código antes (before) o después (after) de que se produzca este evento.
Con los triggers podemos hacer cosas tan interesantes como mantener un log de que usuarios hace modificaciones en una tabla, que usuarios borran registros, o insertan, o lo que se te ocurra.
Para referenciar las columnas de antes y después de que el vento se haya disparado, se usan las palabras clave OLD y NEW. Con la sentencia insert solo se permite NEW, con update se permiten ambas y con delete solo OLD.
Sintaxis necesaria para crear un trigger
-
CREATE TRIGGER <nombre>
-
{BEFORE|AFTER}
-
{INSERT|UPDATE|DELETE}
-
ON
-
<tablename>
-
FOR EACH ROW
-
BEGIN
-
<sentenciasSQL>
-
END;
-
Para poner nombre a los triggers es conveniente seguir una convención que hará más fácil identificar sobre que evento y tabla actúa el trigger. Esta sería una buena forma de nombrar nuestros triggers:
NombreTabla + “_” + abreviatura_tipo_tigger
Por lo tanto para nombrar un triger que se ejecuta sobre la tabla T1 después de un update lo haríamos de la siguiente forma si seguimos esta convención:
“T1_BU”
Esto puede ser útil, pero no es necesario, puedes poner el nombre que quieras a tu trigger.
Para crear triggers en una tabla es necesario hacerlo desde un usuario con permisos para ello. Para dar permiso a un usuario en una tabla para crear un trigger lo haríamos de la siguiente forma:
-
GRANT CREATE TRIGGER ON nombreTabla TO Usuario
-
Vamos a ver un ejemplo sencillo:
Creamos la tabla miTabla
-
CREATE TABLE miTabla( id int , nombre varchar(50) );
-
Y después creamos un trigger que va a crear una variable global con el nombre antiguo antes de ejecutar el update y otra con el nombre nuevo que habrá después de ejecutar el update.
-
delimiter //
-
CREATE TRIGGER miTabla_bu before UPDATE
-
ON miTabla
-
FOR each row
-
begin
-
SET @nombreViejo = OLD.nombre;
-
SET @nombreNuevo = NEW.nombre;
-
end//
-
Vamos a ver otro tigger :
-
CREATE TRIGGER miTabla_bi
-
before INSERT ON miTabla
-
FOR each row
-
begin
-
SET @x = ‘Trigger activado’;
-
SET NEW.nombre = ‘Valor introducido desde el TRIGGER’;
-
end//
-
En esta ocasión, cada vez que se haga un insert sobre la tabla miTabla, se creará una variable global con el valor ‘Trigger activado’ y modificará el valor que se insertará en la columna nombre, por lo que siempre se insertará el valor ‘Valor introducido desde el trigger’.
Si lo que queremos es mantener el control de una tabla para ver quien la modifica y a que hora, podemos crear una tabla donde iremos anotando quien hace cada modificación y anotar los cambios.
Creamos la tabla auxiliar
-
CREATE TABLE controlMiTabla
-
(
-
id int NOT NULL AUTO_INCREMENT,
-
id_registro int,
-
anterior_nombre varchar(50),
-
nuevo_nombre varchar(50),
-
usuario varchar(40),
-
modificado datetime,
-
PRIMARY KEY(id)
-
) ENGINE = InnoDB;
-
Y ahora vamos a crear un trigger que se encargue de llevar un log de quien actualiza la tabla, que valores modifica y a que hora:
-
delimiter //
-
CREATE TRIGGER MiTabla_BU after UPDATE ON miTabla
-
FOR each row
-
begin
-
INSERT INTO controlMiTabla (id_registro, anterior_nombre , nuevo_nombre, usuario , modificado ) VALUES(OLD.id , OLD.nombre , NEW.nombre, CURRENT_USER(), NOW() );
-
end//
-
Y ya tenemos nuestro trigger creado, con el cual llevaremos el control de la tabla.
Esto es recomendable hacerlo solo en las tablas de importancia critica, ya que si no nuestra base de datos crecerá de forma innecesaria.
Como hemos comentado en el post de procedimientos almacenados, tener nuestras funciones y procedimientos en MySQL en lugar de de procesar los datos con algún lenguaje del lado del servidor, como PHP , tiene la ventaja de que viaja menos información de la base de datos al servidor web , con el consiguiente aumento del rendimiento y que estas funciones harán que podamos atacar la base de datos desde cualquier otro lenguaje, como Java o ASP.NET sin tener que volver a procesar los datos otra vez.
MySQL tiene muchas funciones que podemos usar en nuestro procedimientos almacenados y consultas, pero en ocasiones podemos necesitar crear nuestras propias funciones para hacer cosas más especializadas…
Vamos a ver cómo crear funciones en MySQL:
-
DELIMITER //
-
-
CREATE FUCNTION holaMundo() RETURNS VARCHAR(20)
-
BEGIN
-
RETURN ‘HolaMundo’;
-
END
-
//
-
Para comprobar que funciona tecleamos lo siguiente en la consola de MySQL :
-
SELECT holaMundo();
Lo que devuelve el siguiente resultado :
mysql> select holaMundo()// +--------------+ | holaMundo() | +--------------+ | Hola Mundo!! | +--------------+ 1 row in set (0.00 sec)
Para borrar la función que acabamos de crear :
-
DROP FUNCTION IF EXISTS holaMundo
-
Uso de las variables en funciones:
Las variables en las funciones se usan de igual manera que en los procedimientos almacenados, se declaran con la sentencia DECLARE, y se asignan valores con la sentencia SET.
-
DELIMITER //
-
-
CREATE FUNCTION holaMundo() RETURNS VARCHAR(30)
-
BEGIN
-
DECLARE salida VARCHAR(30) DEFAULT ‘Hola mundo’;
-
;
-
SET salida = ‘Hola mundo con VARIABLES’;
-
RETURN salida;
-
END
-
//
-
Esta variable es de ámbito local, y será destruida una vez finalice la función. Cabe destacar el uso de la sentencia DEFAULT en conjunto con DECLARE, que asigna un valor por defecto al declarar la variable.
Uso de parámetros en funciones:
-
DROP FUNCTION IF EXISTS holaMundo
-
-
CREATE FUNCTION holaMundo(entrada VARCHAR(20)) RETURNS VARCHAR(20)
-
BEGIN
-
DECLARE salida VARCHAR(20);
-
SET salida = entrada;
-
RETURN salida;
-
END
-
Ahora hemos creado una función que devuelve el mismo valor que le pasamos como parámetro.
Si tecleamos :
mysql> select holaMundo("nosolocodigo")//
+---------------------------+
| holaMundo("nosolocodigo") |
+---------------------------+
| nosolocodigo |
+---------------------------+
1 row in set (0.00 sec)
Obtenemos como resultado lo mismo que le hemos pasado como párametro, en este caso “nosolocodigo”
Para finalizar, algo un poco más complejo, vamos a crear una función que acepte un dividendo y un divisor y haga una división sin usar el operador división:
-
CREATE FUNCTION divide(dividendo int,divisor int) returns int
-
begin
-
declare aux int;
-
declare contador int;
-
declare resto int;
-
SET contador = 0;
-
SET aux = 0;
-
while (aux + divisor) <= dividendo do
-
SET aux = aux + divisor ;
-
SET contador = contador + 1;
-
end while;
-
SET resto = dividendo - aux ;
-
RETURN contador;
-
end;
-
//
-
Para usarlo, simplemente llamaríamos a la función así:
-
SELECT divide(20,2)
-
Lo que devolvería 10.
Mirar el post sobre el control de flujo con procedimientos almacenados si no entiendes esta última función.
Seguimos con MySQL,hemos visto cómo hacer procedimientos almacenados y cómo controlar el flujo de estos. Ahora le toca el turno a los handlers…
Cuando trabajamos con procedimientos almacenados en MySQL tenemos que tener en cuenta que durante la ejecución de nuestra aplicación se pueden producir errores.
Por ejemplo, si estamos trabajando con el motor de base de datos innoDB y definimos claves ajenas, podrán producirse errores de integridad referencial si intentamos hacer un insert en un campo que clave ajena y el valor que intentamos introducir no existe en la tabla que referencia.
Para llevar el control de estos errores podemos definir handlers en nuestro procedimientos almacenados .
Cada error en MySQL desprende un código de error, el cual tendremos que anotar para manejarlo en nuestro handler.
Ejemplo de un handler
Creamos la siguiente tabla:
-
CREATE TABLE t2(
-
s1 int,
-
PRIMARY KEY (s1))engine=innodb;
-
Después creamos esta otra que contiene una clave ajena que hace referencia a la anterior :
-
CREATE TABLE t3 (
-
s1 int, KEY(s1),
-
FOREIGN KEY (s1) REFERENCES t2 (s1))engine=innodB;
-
Después intentamos insertar un valor en la tabla t3, se trata de un valor que no se encuentra en la columna de t2 que referencia… lo que arroja el siguiente error en la consola de mysql:
-
INSERT INTO t3 VALUES(5);
-
Error:
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`pruebas/t3`, CONSTRAINT `t3_ibfk_1` FOREIGN KEY (`s1`) REFERENCES `t2` (`s1`))
Anota el código de error desprendido por que es lo que necesitamos para crear un handler que maneje este error, en este caso 1452.
Para manejar el error creamos un handler que almacenara el error en una tabla que vamos a crear donde iremos guardando un log de errores…
-
CREATE TABLE error_log(error_message varchar(80));
-
Ahora creamos el procedimiento almacenado que se encargara de introducir datos en la BD y manejar excepciones:
-
delimiter //
-
CREATE procedure procedimientoConHandler(parametro1 int)
-
begin
-
declare exit handler FOR 1452
-
begin
-
INSERT INTO error_log VALUES (concat(‘Time: ‘,current_date,‘. Error de clave ajena para el valor= ‘, parametro1));
-
end;
-
INSERT INTO t3 VALUES (parametro1);
-
.
-
.
-
.
-
end;
-
//
-
Creamos dentro del procedimiento un manejador de errores para el tipo de error deseado para que cuando se produzca el error introduzca en una tabla que indiquemos un log de errores y no falle la aplicación . La palabra exit significa que cuando se acabe la ejecución del handler se sale del procedimiento almacenado, si ponemos continue en lugar de exit, la ejecución de procedimiento almacenado proseguiría.
De esta manera para introducir valores en la base de datos lo haces llamando al procedimiento para que maneje los errores y tener un mayor control sobre la aplicación.
Ya tenemos nuestro procedimiento almacenado creado con control de errores.
Sintaxis para declarar handlers:
declare {exit | continue } handler for {error-number | {SQLSTATE error-string}}
Referencia : Documentación oficial de MySQL
Seguimos con los procedimientos almacenados. Vamos a ver como llevar a cabo el control de flujo de nuestro procedimiento. También es interesante observar el uso de las variables dentro de los procedimientos. Si se declara una variable dentro de un procedimiento mediante el código :
-
declare miVar int;
-
Esta tendrá un ámbito local y cuando se acabe el procedimiento no podrá ser accedida. Una vez la variable es declarada, para cambiar su valor usaremos la sentencia SET de este modo :
-
SET miVar = 56 ;
-
Para poder acceder a una variable a la finalización de un procedimiento se tiene que usar parámetros de salida.
Vamos a ver unos ejemplos para comprobar lo sencillo que es :
IF THEN ELSE
-
-
delimiter //
-
CREATE procedure miProc(IN p1 int) /* Parámetro de entrada */
-
begin
-
declare miVar int; /* se declara variable local */
-
SET miVar = p1 +1 ; /* se establece la variable */
-
IF miVar = 12 then
-
INSERT INTO lista VALUES(55555);
-
else
-
INSERT INTO lista VALUES(7665);
-
end IF;
-
end;
-
//
-
SWITCH
-
-
delimiter //
-
CREATE procedure miProc (IN p1 int)
-
begin
-
declare var int ;
-
SET var = p1 +2 ;
-
case var
-
when 2 then INSERT INTO lista VALUES (66666);
-
when 3 then INSERT INTO lista VALUES (4545665);
-
else INSERT INTO lista VALUES (77777777);
-
end case;
-
end;
-
//
-
Creo que no hacen falta explicaciones.
COMPARACIÓN DE CADENAS
-
-
delimiter //
-
CREATE procedure compara(IN cadena varchar(25), IN cadena2 varchar(25))
-
begin
-
IF strcmp(cadena, cadena2) = 0 then
-
SELECT "son iguales!";
-
else
-
SELECT "son diferentes!!";
-
end IF;
-
end;
-
//
-
La función strcmp devuelve 0 si las cadenas son iguales, si no devuelve 0 es que son diferentes.
USO DE WHILE
-
-
delimiter //
-
CREATE procedure p14()
-
begin
-
declare v int;
-
SET v = 0;
-
while v < 5 do
-
INSERT INTO lista VALUES (v);
-
SET v = v +1 ;
-
end while;
-
end;
-
//
-
Un while de toda la vida.
USO DEL REPEAT
-
-
delimiter //
-
CREATE procedure p15()
-
begin
-
declare v int;
-
SET v = 20;
-
repeat
-
INSERT INTO lista VALUES(v);
-
SET v = v + 1;
-
until v >= 1
-
end repeat;
-
end;
-
//
-
El repeat es similar a un “do while” de toda la vida.
LOOP LABEL
-
-
delimiter //
-
CREATE procedure p16()
-
begin
-
declare v int;
-
SET v = 0;
-
loop_label : loop
-
INSERT INTO lista VALUES (v);
-
SET v = v + 1;
-
IF v >= 5 then
-
leave loop_label;
-
end IF;
-
end loop;
-
end;
-
//
-
Este es otro tipo de loop, la verdad es que teniendo los anteriores no se me ocurre aplicación para usar este tipo de loop, pero es bueno saber que existe por si algún día te encuentras algún procedimiento muy antiguo que lo use. El código que haya entre loop_label : loop y end loop; se ejecutara hasta que se encuentre la sentencia leave loop_label; que hemos puesto en la condición, por lo tanto el loop se repetirá hasta que la variable v sea >= que 5.
El loop puede tomar cualquier nombre, es decir puede llamarse miLoop: loop, en cuyo caso se repetirá hasta que se ejecute la sentencia leave miLoop.
Con esto ya podemos empezar a crear procedimientos medianamente complejos y útiles.