Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
FIREBIRD:
SQL
PROCEDIMENTAL
(PSQL)
1.- INTRODUCCION.............................................................................................................................. 1
2.- EXTENSIONES DEL LENGUAJE................................................................................................... 2
2.1.- Terminadores. .............................................................................................................................. 2
2.2.- Variables...................................................................................................................................... 3
2.3.- Sentencias bsicas........................................................................................................................ 4
2.4.- Cursores. ...................................................................................................................................... 5
2.5.- Sentencias control de flujo. ......................................................................................................... 8
2.6.- Ejecucin de cdigo..................................................................................................................... 9
2.7.- Eventos. ....................................................................................................................................... 9
3.- PROCEDIMIENTOS ALMACENADOS........................................................................................ 11
4.- TRIGGERS....................................................................................................................................... 13
5.- EXCEPCIONES ............................................................................................................................... 16
1.- INTRODUCCION
Uno de los grandes beneficios de la implementacin de SQL en Firebird es la posibilidad de
compilar y ejecutar modulos de cdigo interno (procedimientos almacenados y triggers) desarrollados
por un programador. Para ello se tiene PSQL, una sintaxis que combina sentencias de DML con una
extensin para programacin.
Se habla en este caso de programacin en el lado del servidor, ya que el cdigo se ejecutar en
la mquina del servidor por el propio servidor. Esto tiene sus ventajas:
- Diseo modular: Todas las aplicaciones que acceden a la misma base de datos comparten
los procedimientos almacenados y por tanto se centralizan las reglas de empresa, se
reutiliza cdigo y se reduce el tamao de las aplicaciones.
- Facilidad en mantenimiento: Cuando se realiza un cambio en un procedimiento, ste se
traslada de forma automtica a todas las aplicaciones que lo usan.
- Mejora de eficiencia: El procesado complejo se realiza en el servidor reduciendo el trafico
de red y la carga en los clientes.
- Economa en la arquitectura: Las aplicaciones clientes se pueden orientar hacia la captura
de datos y tareas interactivas mientas el trabajo complejo con datos se realiza en el
servidor.
- Funcionalidad extra: Operaciones que no se pueden realizar fcilmente mediante sentencias
SQL pueden implementarse mediante procedimientos almacenados.
- Trigger: Es una rutina asociada a una tabla o vista que se lanza de forma automtica
cuando se realiza una operacin de insercin, borrado o actualizacin de una fila. Un
trigger nunca se llama directamente.
Se suelen usar los triggers para realizar actualizaciones de datos ante cambios en filas,
validar datos de entrada, transformaciones de datos, actualizaciones de integridad
referencial en cascada o para hacer vistas de solo lectura actualizables.
Un aspecto importante a tener en cuenta con los mdulos de PSQL es que no aportan control de
transacciones. Un mdulo se ejecuta siempre en el mbito de una transaccin abierta previamente.
Desde el mdulo no puede ser confirmada ni cancelada, lo nico que se puede es lanzar una excepcin
ante un problema detectado. La aplicacin que ha llamado al mdulo ser la encargada de realizar la
finalizacin apropiada de la transaccin (confirmar o deshacer).
2.1.- Terminadores.
Muchos de los elementos que nos encontramos en un mdulo se deben indicar con el
terminador ;. Ya que un mdulo es una sla sentencia finalizada con un terminador es necesario
diferenciar ste de los elementos del mdulo. Esto se consigue mediante la sentencia SET TERM. Por
ejemplo una definicin tipica de un procedimiento sera:
SET TERM ;^ -- fija de nuevo el terminador como ; y acaba la sentencia con el terminador actual ^
2.2.- Variables.
En PSQL se pueden usar 5 tipos de variables en el cuerpo de un mdulo, con algunas
restricciones segn sea procedimiento o trigger:
- Variables locales, usadas para mantener valores locales en un mdulo.
- Las variables NEW.columna y OLD.columna usadas en los triggers para almacenar los
valores modificados de la fila o los antiguos.
- Variables de contexto.
- Argumentos de entrada pasados como constantes en los procedimientos almacenados.
- Argumentos de salida, usados para devolver valores en los procedimientos almacenados.
Las variables pueden usarse en sentencias SQL dentro de los mdulos aunque en este caso se
preceden por : para diferenciarlas de las columnas de las tablas.
FOR SELECT cod_accta FROM ACCIONISTAS
INTO :variable DO -- Variable lleva : al estar dentro de un select.
BEGIN
otra = otra + variable variable no lleva los : al no aparecer en una sentencia select.
END
Una variable se asigna mediante el = ( variable = expresin), en donde se puede asignar a una
variable cualquier expresin en la que usemos variables, operadores, funciones SQL.
codigo = GEN_ID(generador,1);
codigo = codigo + IIF(codigo<0,0,codigo);
Las variables locales se declaran, una por una, antes del primer BEGIN siendo su mbito
nicamente el cuerpo del procedimiento o trigger. En la misma sentencia es posible darles un valor:
En PSQL se pueden usar todas las variables de contexto y literales comentados en temas
anteriores como NOW, CURRENT_USER, etc. Adems se define la variable ROW_COUNT que
contiene el nmero de filas afectadas por la ltima sentencia de DML ejecutada.
A los argumentos de entrada se les puede asignar un valor por defecto lo que hace que se pueda
omitir en la llamada al procedimiento. En este caso, una ver definido uno, todos los siguientes deben
tener tambin un valor por defecto y omitirse en la llamada.
Los argumentos de salida se definen en los procedimientos almacenados para que puedan
devolver valores a la aplicacin que los llama. Se declaran en la cabecera pudindose usar en cualquier
punto del cuerpo.
OLD y NEW son exclusivos de los triggers. OLD contiene los valores de la fila para la que se
activa el trigger antes de la modificacin o borrado. NEW los valores de la fila modificados o
insertados. Estas variables se vern con ms detenimiento con los triggers.
En PSQL se trabaja con la sentencia condicional IF THEN . ELSE. sta tiene como
sintaxis:
IF (<condicion>)
THEN <sentencia compuesta>
[ELSE <sentencia compuesta>]
La clusula <condicion> es un predicado que se evalua a true o false. Si vale true se ejecuta la
sentencia del THEN. Si vale false se evalua, si existe, la sentencia del ELSE.
WHILE (<condicion>) DO
<sentencia compuesta>
Por ejemplo podramos tener, el siguiente procedimiento que suma todos los nmeros desde el
0 hasta el que se indica como parmetro de entrada:
2.4.- Cursores.
Un cursor es un elemento que nos permite obtener los valores de una fila perteneciente a un
conjunto de salida obtenido a partir de una sentencia SELECT. En Firebird se trabaja tanto con
cursores explcitos, definidos explcitamente, como con cursores implcitos, aparecen por debajo de
una sentencia sin que nos demos cuenta.
- SELECT . INTO ..: Se usa para asignar los campos de la nica fila obtenida en una
sentencia a unas variables. Es semejante a una asignacin en la que la expresin se obtiene
de la sentencia SELECT.
SELECT first 1 cod_accta, nom_accta FROM accionistas slo puede devolver una fila
INTO :var_codigo, :var_nombre -- se almacenan los campos en las variables indicadas
La sentencia SELECT debe devolver como mximo una sla lnea. Se deben indicar tantas
variables como campos se devuelvan.
- FOR SELECT: Se utiliza para recorrer una sentencia SELECT que devuelve una o ms
filas realizando operaciones sobre los datos devueltos.
END
En este caso se deben indicar tantas variables y del mismo tipo como columnas devuelva la
sentencia. Por ejemplo podemos tener un procedimiento que obtiene la mxima cotizacin
para un banco dado y actualiza el valor en la tabla bancos.
sentencia = select first 1 cod_banco from bancos; --crea la sentencia en tiempo de ejecucin
EXECUTE STATEMENT sentencia INTO :codigo; -- se ejecuta la sentencia almacenando el
resultado en una variable
Mediante esta sentencia se pueden ejecuta sentencias que no devuelven filas como
INSERT, UPDATE, DELETE, EXECUTE PROCEDURE y cualquier sentencia DDL
excepto las de CREATE/DROP DATABASE. Se tiene que tener en cuenta que dentro de
un mdulo no es posible ejecutar sentencias DDL directamente.
Por ejemplo para ejecutar un procedimiento que se pasa como parmetro podramos tener:
CREATE PROCEDURE EJECU_PROCE(PROCE VARCHAR(30))
AS
DECLARE VARIABLE SENTENCIA VARCHAR(1000);
BEGIN
SENTENCIA = EXECUTE PROCEDURE || PROCE;
EXECUTE STATEMENT SENTENCIA;
END^
- FOR EXECUTE STATEMENT: Al igual que FOR SELECT permite recorrer las filas
devueltas al ejecutar una sentencia.
Cuando usemos esta sentencia tenemos que tener en cuenta que debemos garantizar que la
cadena que generemos sea correcta, puesto que, a diferencia de FOR SELECT, la sentencia
no es validada en el momento de definir el procedimiento. Tambin tenemos que tener en
cuenta que la sentencia se ejecutar de forma m lenta ya que tiene que ser compilada cada
vez que se vaya a ejecutar.
Por ejemplo si queremos crear un procedimiento que concatene un campo cadena de una
tabla podramos tener:
Por ejemplo si queremos un procedimiento que devuelva un nombre propio para cada banco
podramos tener:
Se podra llamar
Los cursores explcitos son aquellos que se definen de forma explcita mediante una sentencia
de declaracin. En Firebird nos encontramos con las siguientes sentencias de gestin de cursores:
Con los cursores explcitos se tienen que tener una serie de consideraciones:
- Dos cursores no pueden tener el mismo nombre aunque si un cursor y una variable. Los
nombres de cursores deben ser nicos.
- Intentar hacer un fetch (devolver los valores para la fila actual) en un cursor no abierto da
un error.
- Se usa ROW_COUNT para comprobar si fetch devuelve o no filas.
Adems de los anteriores se tiene la sentencia LEAVE. Se usa en los bucles para salir de ellos.
Hace que se pase a la siguiente sentencia fuera del bucle.
CONT=0;
WHILE (1=1) DO -- esta codicin supone un bucle infinito.
BEGIN
CONT=CONT+1;
IF (CONT>9) THEN
LEAVE; -- solo se puede salir mediante LEAVE.
END
.. cuando se ejecuta LEAVE se va a la siguiente sentencia
Esta sentencia permite llamar a un procedimiento almacenado indicando valores para los
argumentos de entrada. Si se definen argumentos de salida se pueden devolver los valores en las
variables indicadas.
Su sintaxis es:
EXECUTE BLOCK [ (parmetro tipo = ?[, parametro tipo = ? ...) ]
[ RETURNS (parametro tipo[, param datatype ...]) ]
AS
[DECLARE VARIABLE var datatype; ...]
BEGIN
...
END
2.7.- Eventos.
Los eventos son un mecanismo por el que desde Firebird se pueden enviar seales a las
aplicaciones para notificar cualquier suceso de forma asncrona, es decir, sin que la aplicacin tenga
que estar a la espera.
POST_EVENT evento;
Como se ve se pueden indicar una lista de argumentos de entrada a los que se les pueden
asignar valores por defecto. En este caso todos los siguientes argumentos de entrada deben tener
tambin definidos valores por defecto.
CREATE PROCEDURE PRUEBA (entrada integer = 10) se define un argumento de entrada con
valor por defecto 10
RETURNS (salida integer) -- se define un argumento de salida
AS
DECLARE VARIABLE NUEVA INTEGER=3; -- declaramos una variable local
BEGIN
/* Procedure body */
nueva=nueva+entrada+5; -- usamos las variables locales y los argumentos
salida=nueva; -- se rellena un argumento de salida
SUSPEND; -- se envia la fila a la aplicacin que lo llame.
END
select * from prueba se llama como procedimiento seleccionable sin rellenar los argumentos
select * from prueba(5) se llama al procedimiento seleccionable indicando el argumento
..
AS
DECLARE VARIABLE varia integer;
BEGIN
.
execute procedure prueba(3) RETURNING_VALUES (varia);
.
END
Una ventanja de los procedimientos almacenados es que se pueden definir de forma recursiva,
es decir, se pueden llamar a s mismos.
4.- TRIGGERS
Un trigger o disparador es un mdulo que se ejecuta de forma automtica cuando se cambia el
estado de una fila como respuesta a una peticin. Los triggers no se pueden invocar por aplicaciones u
otros procedimientos. Adems, no pueden tener argumentos de entrada o salida.
Los triggers se ejecutan a nivel de fila, una por cada imagen de fila cambiada y se establece un
alto grado de granularidad en cuanto a cuando, en que orden condiciones se dispara un trigger
particular. Esto se establece mediante la fase, evento y secuencia.
Firebird permite ejecutar mltiples triggers para cada combinacin fase/evento. Para establecer
el orden en el que se ejecutan se define un nmero de secuencia. Por defecto vale 0. Si se indican
nmeros de secuencia se ejecutan los triggers en orden ascendente. Cuando varios triggers tienen
definidos el mismo nmero de secuencia, se establece un orden alfabtico por sus nombres.
Un trigger puede estar activo o inactivo. Slo se disparan los triggers activos. El estado se
puede modificar mediante la sentencia ALTER.
{BEFORE |AFTER }
{{DELETE | INSERT | UPDATE }
| { DELETE OR {[INSERT [OR UPDATE]} | {INSERT OR []} | {UPDATE OR
[]}}}
[POSITION numero]
AS aqu empieza el cuerpo del trigger
[DECLARE [VARIABLE] variable tipo[{= | DEFAULT} valor];
BEGIN
<sentencias>
END <terminador>
Si usamos la sintaxis BEFORE INSERT OR DELETE OR UPDATE, se puede usar, dentro del
cuerpo, las variables de contexto INSERTING, UPDATING y DELETING que indican ante que tipo
de evento se est respondiendo.
Adems de las variables anteriores, PSQL aporta las variables OLD y NEW. Contienen
respectivamente los valores de las columnas existentes y los nuevos. No siempre estn disponibles.
Por ejemplo ante un evento DELETE, solo tenemos valores OLD mientras que ante un INSERT solo
tenemos NEW.
Los triggers se usan para proporcionar valores por defecto, validar y transformar entradas del
usuario, actualizar otras tablas relacionadas o para garantizar reglas de integridad.
Un uso muy comn de los triggers es implementar las columnas autonumricas haciendo uso
de un generador. Por ejemplo si tubieramos un generador llamado gen_cod_banco para generar
codigos de bancos para la tabla bancos podramos tener el trigger:
Un trigger puede ser modificado mediante las sentencia ALTER TRIGGER y CREATE OR
ALTER TRIGGER. Ambas tienen una sintaxis semejante a la de CREATE TRIGGER con la nica
diferencia que en ALTER TRIGGER no se indica la tabla sobre la que se trabaja:
5.- EXCEPCIONES
PSQL aporta un mecanismo para la gestin de errores. De forma estndar los mdulos
gestionan las excepciones parando la ejecucin, deshaciendo el trabajo hecho desde la sentencia
BEGIN inicial y pasando uno o ms mensajes de error.
En donde nombre es un identificador de cmo mximo 31 caracteres y mensaje una cadena con
conjunto de caracteres NONE. Por ejemplo podramos tener:
Se puede borrar una excepcin (DROP EXCEPTION <nombre>) o modificar una existente
(ALTER EXCEPTION <nombre> <mensaje>).
Las excepciones definidas internamente son lanzadas por el sistema en respuesta a errores que
requieren que se pare la ejecucin. stas cubren un gran rango de condiciones incluyendo violaciones
de restricciones de integridad, desbordamientos aritmticos y de cadena, referencias a objetos no
existentes, corrupcin de datos, etc. Las excepciones GDSCODE y SQLCODE son las mismas que
nos encontramos cuando se produce un error al ejecutar una sentencia de DSQL.
Las excepciones de usuario, slo disponibles en mdulos PSQL, son usadas para codificar
nuestros propios errores en la lgica de los programas.
De esta forma podramos encontrarnos con un trigger usado para validar el nombre de un banco
insertado o modificado:
CREATE TRIGGER BI_BANCOS FOR BANCOS trigger para validar el nombre del banco
BEFORE INSERT OR UPDATE
Si usamos esta sentencia sin ningn parmetro se puede relanzar la excepcin para que la
gestione otro bloque. Otro uso posible es la de asignarle el mensaje directamente en tiempo de
ejecucin.
Adems de poder lanzar nuestras propias excepciones Firebird aporta un mecanismo para
gestionar, dentro de un mdulo, las excepciones generadas y as poder continuar con la ejecucin de
nuestro cdigo. Esto se consigue mediante la sentencia WHEN:
Una sentencia WHEN siempre se tiene que ubicar inmediatamente antes de una sentencia END
(no puede haber otras sentencias entre ellas).
CREATE TRIGGER BI_BANCOS FOR BANCOS trigger para validar el nombre del banco
BEFORE INSERT OR UPDATE
AS
BEGIN
IF (NEW.NOM_BANCO NOT CONTAINING BANCO) THEN si el nombre no cumple la
condicin
EXCEPTION BANCO_ERRONEO; lanzo la excepcin de usuario.
Firebird aporta dos variables de contexto para poder consultar el error producido: SQLCODE y
GDSCODE. Estas variables se asignan de forma automtica con el cdigo de error permaneciendo en
el bloque de gestin de error. Fuera de este bloque siempre valen 0.