PDA

Ver la Versión Completa : Más trucos con generadores


dec
30-06-2006, 18:06:50
Ahora que ya sabe como crear y destruir un generador nos queda conocer cómo podemos obtener el valor actual del generador. ¡Elemental, Watson!, pensará usted. Hasta el alcalde de mi pueblo sabe que existe la función gen_id, que recibe un nombre de generador y un incremento, lo aplica al generador y devuelve el valor del mismo. Casi siempre el generador se utiliza en triggers o procedimientos como los siguientes:


create trigger AsignarCodigoFormaPago for FormasPago
active before insert position 0 as
begin
if (new.Codigo is null) then
new.Codigo = gen_id(FormaPagoGen);
end!

create procedure DameUnNumero returns(Codigo integer) as
begin
Codigo = gen_id(OtroGenerador, 1);
end!


Ante tanta sabiduría me siento obligado a preguntarle algo: ¿qué valor devuelve gen_id, el que tenía el generador antes del incremento, o el valor posterior? Pues es el valor posterior al incremento el que se retorno. Claro, no esperaba otra cosa de usted...

¿Y cómo puedo obtener el valor actual del generador, pero sin modificarlo? La primera vez que me lo preguntaron, contesté algo que aún me avergüenza recordar:


// ¡¡¡MUY MALO!!!
create procedure ValorActual returns(Codigo integer) as
begin
Codigo = gen_id(OtroGenerador, 1);
Codigo = gen_id(OtroGenerador, -1);
end!


¿Funcionar? Creo que sí, pero funciona a lo bestia. Con más experiencia sobre mis espaldas, ahora me doy cuenta de que el siguiente procedimiento es más racional:


create procedure ValorActual returns(Codigo integer) as
begin
Codigo = gen_id(OtroGenerador, 0);
end!


De todos modos sigue existiendo un problema. Supongamos que estamos desarrollando una herramienta de diseño, al estilo de SQL Explorer, o de Marathon. En tal caso, no tendremos a mano un procedimiento como el anterior para cada uno de los generadores de la base de datos. Pero el problema no es grave: gen_id es una función como cualquier otra (aunque causa un efecto secundario), y puede colocarse en una cláusula select. Inmediatamente me viene a la mente la tabla Dual de Oracle: una tabla predefinida que siempre contiene una sóla fila. Si tuviésemos esta tabla en InterBase, nos bastaría ejecutar la siguiente instrucción para conocer el valor actual de un generador:


// ¡¡¡NO FUNCIONA, LA TABLA Dual ES DE ORACLE, NO DE INTERBASE!!!
select gen_id(OtroGenerador, 0) from Dual


Bien, no existirá Dual en InterBase, pero sí tenemos la tabla interna del sistema RDB$DATABASE, que hasta donde conozco, siempre tiene una sola fila. Entonces podemos utilizar esta variante:


// VARIANTE CORRECTA
select gen_id(OtroGenerador, 0) from RDB$DATABASE


En realidad, SQL Explorer utiliza este otro truco:


// VARIANTE DE SQL EXPLORER
select distinct gen_id(OtroGenerador, 0) from RDB$GENERATORS


Por supuesto, el resultado del select anterior ¡siempre tiene una sola fila!.