Está en la página 1de 19

Firebird: SQL Procedimental (PSQL) Tema 6

FIREBIRD:
SQL
PROCEDIMENTAL
(PSQL)

Vicente Tejero Trueba Pag 1 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

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

Vicente Tejero Trueba Pag i IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

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.

Cada mdulo creado podr ser:

- Procedimiento almacenado: Se pueden utilizar como procedimientos seleccionables


(sustituyen a una tabla o vista en una sentencia SELECT) o como procedimientos
ejecutables (ejecutar una operacin o conjunto de operaciones en el lado del servidor) que
se pueden llamar mediante EXECUTE PROCEDURE o desde otro procedimiento o trigger.

- 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).

En este tema veremos los ejemplos a partir de la base de datos de bancos:

Vicente Tejero Trueba Pag 1 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

2.- EXTENSIONES DEL LENGUAJE.


Los mdulos PSQL no son ms que sentencias SQL que comienzan con una clusula CREATE
y finalizan con un terminador. En la definicin del mdulo apareceran un nmero variable de
elementos como clausulas, palabras clave, bloques de sentencias, bucles, etc.

Un mdulo de PSQL se define estableciendo dos elementos fundamentales:


- La cabecera: En ella se incluyen todos los elementos de definicin del procedimiento o
trigger como nombre del mdulo, parmetros de entrada y/o salida para los procedimientos,
tipo de trigger, etc.
- El cuerpo: En el se definen todos los elementos que desarrollan el mdulo como la
declaracin de variables, el bloque de sentencias (entre el BEGIN END) y los manejadores
de excepcin.

As tendramos que en un procedimiento:


-- se inicia la cabecera
CREATE PROCEDURE procedimiento (entrada INTEGER) RETURNS (salida INTEGER)
--se acaba la cabecera
AS -- se inicia el cuerpo
DECLARE VARIABLE variable INT;
BEGIN
variable = entrada /2;
salida =variable;
END
-- fin del cuerpo

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 ^; -- establece como terminador el ^ a partir de esta sentencia.


CREATE PROCEDURE MI_PROCEDIMIENTO
.
AS
BEGIN

Vicente Tejero Trueba Pag 2 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6
sentencia; --sentencia acabada en ;
END ^ -- finaliza la definicin del procedimiento mediante el terminador indicado, el ^

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:

DECLARE VARIABLE variable


{<tipo>
| <dominio>
| TYPE OF <dominio>
| TYPE OF COLUMN <tabla o vista>.<columna>}
[{DEFAULT valor } | {= valor}];

DECLARE VARIABLE variable INTEGER DEFAULT 0;


DECLARE VARIABLE cadena CHAR(20) = hola;

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.

Los argumentos de entrada se definen en los procedimientos almacenados para que la


aplicacin pueda pasar valores al mismo. Son declarados en la cabecera pudindose usar en cualquier
punto del cuerpo. Los argumentos de entrada son siempre pasados por valor, por lo que cualquier
cambio que se produzca dentro del cuerpo no se enva al exterior.

Vicente Tejero Trueba Pag 3 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

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.

CREATE PROCEDURE procedimiento


[({arg_entrada <tipo> [= valor_defecto]}[, ] )] argumentos de entrada.
[RETURNS ({arg_salida <tipo>}[, ] )] argumentos de salida.

CREATE PROCEDURE procedimiento (entrada INTEGER=0) RETURNS (salida INTEGER)


AS
DECLARE VARIABLE variable INT;
BEGIN
variable = entrada /2;
salida =variable;
END

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.

2.3.- Sentencias bsicas.


En PSQL existe la sentencia bloque, es decir, aquella que permite definir en su interior otras
sentencias. En PSQL es BEGIN . END. Se usa tanto para el bloque principal como para otros
internos.

En PSQL se trabaja con la sentencia condicional IF THEN . ELSE. sta tiene como
sintaxis:

IF (<condicion>)
THEN <sentencia compuesta>
[ELSE <sentencia compuesta>]

<sentencia compuesta> = {<bloque> | <sentencia>;}

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.

Podemos utilizar cualquier predicado. Por ejemplo podramos tener:

IF (EXISTS (select * from accionistas where cod_accta=:cod)) THEN


var=BUENA;

IF (nombre in (PEDRO,JUAN)) THEN


var= nombre;
ELSE

Vicente Tejero Trueba Pag 4 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6
var=desconocido;

En PSQL se define una sentencia de tipo bucle: WHILE DO.

WHILE (<condicion>) DO
<sentencia compuesta>

<sentencia compuesta> = {<bloque> | <sentencia>;}

Por ejemplo podramos tener, el siguiente procedimiento que suma todos los nmeros desde el
0 hasta el que se indica como parmetro de entrada:

CREATE PROCEDURE SUMA (i INTEGER) RETURNS (su INTEGER)


AS
BEGIN
su=i;
i=i-1;
WHILE (i>0) DO
BEGIN
su=su+i;
i=i-1;
END
END

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.

En los cursores implcitos nos encontramos con:

- 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.

FOR SELECT <lista columnas>


FROM .
INTO <lista variables> DO
BEGIN
<sentencias>
[SUSPEND;]

Vicente Tejero Trueba Pag 5 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

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.

CREATE PROCEDURE ACT_PRE_MAX (banco INTEGER)


AS
DECLARE VARIABLE MAXIMO NUMERIC(12,2);
DECLARE VARIABLE VALOR NUMERIC(12,2);
BEGIN
MAXIMO =0;
FOR SELECT pre_ac_fe FROM cotizaciones
WHERE cod_banco=:banco
INTO :VALOR DO
BEGIN
IF (VALOR>MAXIMO) THEN
VALO=MAXIMO;
END
UPDATE BANCOS SET PRE_MA_AC=:MAXIMO
WHERE COD_BANCO=:BANCO;
END ^

- EXECUTE STATEMENT . INTO: Es equivalente a SELECT INTO con la diferencia


de que aqu lo que se indica es una cadena que contiene la sentencia a ejecutar. Esto nos
permite definir sentencias dinmicas.

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.

FOR EXECUTE STATEMENT sentencia


INTO <lista variables> DO
BEGIN
<sentencias>
END

Vicente Tejero Trueba Pag 6 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

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:

CREATE PROCEDURE CONCATENAR (TABLA VARCHAR(30), CAMPO VARCHAR(30))


RETURNS (CADENA VARCHAR(2000))
AS
DECLARE VARIABLE SENTENCIA VARCHAR(1000);
DECLARE VARIABLE VALOR VARCHAR(1000);
BEGIN
CADENA=;
SENTENCIA = SELECT || CAMPO || FROM || TABLA;
FOR EXECUTE STATEMENT SENTENCIA
INTO :VALOR DO
BEGIN
CADENA = CADENA || , +VALOR;
END
END ^

Mediante la sentencia FOR SELECT es posible definir los procedimientos almacenados


seleccionables, es decir, aquellos que pueden actuar como tablas en sentencias SELECT, en
contraposicin con los procedimientos almacenados ejecutables que son aquellos que ejecutan una
operacin programada.
Un procedimiento almacenado ejecutable se obtiene con la inclusin de una sentencia
SUSPEND dentro del bucle DO. Esto causa que, una vez asignadas las variables correspondientes al
cursor, el bucle se pare hasta que la fila sea recogida por el servidor.

Por ejemplo si queremos un procedimiento que devuelva un nombre propio para cada banco
podramos tener:

CREATE PROCEDURE MIS_BANCOS () RETURNS (COD_BANCO INT, MI_NOMBRE


VARCHAR(100))
AS
BEGIN
FOR SELECT COD_BANCO,NOM_BANCO
FROM BANCOS
INTO :COD_BANCO, MI_NOMBRE DO
BEGIN
MI_NOMBRE=EL BANCO ES || MI_NOMBRE;
SUSPEND;
END
END ^

Se podra llamar

select * from MIS_BANCOS()

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:

Vicente Tejero Trueba Pag 7 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

DECLARE [VARIABLE] <nombre cursor> CURSOR FOR ( <sentencia select> );


OPEN < nombre cursor >;
FETCH < nombre cursor > INTO <variable> [, <variable> ...];
CLOSE < nombre cursor >;

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.

Por ejemplo el procedimiento MIS_BANCOS mediante cursores podra ser:

CREATE PROCEDURE MIS_BANCOS () RETURNS (COD_BANCO INT, MI_NOMBRE


VARCHAR(100))
AS
DECLARE MI_CURSOR CURSOR FOR SELECT COD_BANCO,NOM_BANCO
FROM BANCOS declaro el cursor para la sentencia
BEGIN

OPEN MI_CURSOR; -- abro el cursor.


FETCH MI_CURSOR INTO :COD_BANCO, MI_NOMBRE; --obtengo los valores para la fila
WHILE (ROW_COUNT>0) DO
BEGIN
MI_NOMBRE=EL BANCO ES || MI_NOMBRE;
SUSPEND;
FETCH MI_CURSOR INTO :COD_BANCO, MI_NOMBRE;
END
CLOSE MI_CURSOR; -- cierro el cursor.
END ^

2.5.- Sentencias de control de flujo.


Firebird proporciona varias sentencias que afectan al control de flujo:
- SUSPEND: ya se ha comentado anteriormente.
- EXIT: Hace que se vaya al final de un procedimiento.
- END: Finaliza la ejecucin.

Segn se tenga un procedimiento ejecutable, seleccionable o un trigger estas sentencias pueden


trabajar con ciertos matices:

MODULO SUSPEND EXIT END


Procedimiento Se suspende la ejecucin Devuelve los Devuelve el control a la aplicacin
seleccionable hasta que la aplicacin valores (si los y pone SQLCODE a 100
solicite un nuevo registro hay) y salta al
al procedimiento END final
Procedimiento Salta al END final (no se Salta al END Devuelve los valores y pasa el
ejecutable aconseja) final control a la aplicacin.
trigger No se usa Salta al END Hace que se ejecute el siguiente
final trigger en la misma fase (AFTER o
BEFORE)si hay. En otro caso
termina el trigger.

Vicente Tejero Trueba Pag 8 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

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

2.6.- Ejecucin de cdigo.


En PSQL es posible ejecutar directamente procedimientos almacenados, sentencias y ms
recientemente bloques de cdigo.

Un procedimiento almacenado se ejecuta mediante la sentencia EXECUTE PROCEDURE.

EXECUTE PROCEDURE procedimiento [(] [argumento [, .]] [)]


[RETURNING_VALUES variable[,];

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.

EXECUTE PROCEDURE suma 5 RETURNING_VALUES :resultado; -- se llama al procedimiento


suma visto en ejemplos anteriores.

Recientemente Firebird ha incluido la sentencia EXECUTE BLOCK. Esta sentencia no es


realmente una sentencia de PSQL aunque hace que un PSQL dinmico est disponible en una
sentencia SELECT. Tiene el efecto de que un bloque de cdigo de PSQL se pueda ejecutar en una
sentencia de DSQL como si fuera un procedimiento almacenado.

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.

Se envan eventos mediante:

Vicente Tejero Trueba Pag 9 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

POST_EVENT evento;

Vicente Tejero Trueba Pag 10 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

3.- PROCEDIMIENTOS ALMACENADOS


Un procedimiento almacenado es un mdulo escrito en PSQL, compilado por el interprete de
lenguaje binario de Firebird y almacenado como cdigo ejecutable en los metadatos de la base de
datos. Una vez compilado, el procedimiento puede ser invocado directamente desde una aplicacin u
otro mdulo PSQL usando EXECUTE PROCEDURE o una sentencia SELECT.

Se distinguen dos tipos de procedimientos almacenados:


- Ejecutables: Son los procedimientos que se llaman con la sentencia EXECUTE
PROCEDURE y que pueden devolver, opcionalmente, una nica fila de uno o ms valores.
Se usan a menudo para realizar operaciones de insercin, actualizacin o borrado, o para
larzar un conjunto de operaciones.
- Seleccionable: Los procedimientos seleccionables son escritos con extensiones del
lenguaje para generar un conjunto de salida de mltiples filas que es devuelto usando una
sentencia SELECT.

En principio no se hace distincin entre procedimiento ejecutable o seleccionable. Cuando son


llamados, y no se ajustan a la forma de llamada, el sistema genera una excepcin. Es por tanto funcin
del programador garantizar que se usan de la forma apropiada.

Un procedimiento se crea mediante la sentencia CREATE PROCEDURE:

CREATE PROCEDURE procedimiento


[(argumento tipo[{= | DEFAULT} valor]
[, argumento tipo[{= | DEFAULT} valor])]
[RETURNS (argumento tipo [, argumento tipo])]
AS aqu empieza el cuerpo
[DECLARE [VARIABLE] variable tipo[{= | DEFAULT} valor];
BEGIN
<sentencias>
END <terminador>

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.

Se puede indicar uno o mas argumentos de salida mediante la clusula RETURNS.

Se pueden declarar variables antes del bloque principal.

Por ejemplo podramos tener

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

Vicente Tejero Trueba Pag 11 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

El anterior procedimiento se podra llamar como:

select * from prueba se llama como procedimiento seleccionable sin rellenar los argumentos
select * from prueba(5) se llama al procedimiento seleccionable indicando el argumento

o como procedimiento ejecutable dentro de otro

..
AS
DECLARE VARIABLE varia integer;
BEGIN
.
execute procedure prueba(3) RETURNING_VALUES (varia);
.
END

En este caso la llamada al procedimiento ha funcionado tanto como seleccionable como


ejecutable ya que devolva como mximo una fila. Si el procedimiento se hubiera definido para que
devolviera mas de una fila (Sentencia suspend dentro de un for select , ) nos habra dado una
excepcin al llamarlo mediante EXECUTE PROCEDURE.

Una ventanja de los procedimientos almacenados es que se pueden definir de forma recursiva,
es decir, se pueden llamar a s mismos.

En Firebird se establecen varios mecanismos para modificar un procedimiento almacenado:

{CREATE | ALTER | RECREATE | CREATE OR ALTER} PROCEDURE procedimiento


[(argumento tipo[{= | DEFAULT} valor]
[, argumento tipo[{= | DEFAULT} valor])]
[RETURNS (argumento tipo [, argumento tipo])]
AS aqu empieza el cuerpo
[DECLARE [VARIABLE] variable tipo[{= | DEFAULT} valor];
BEGIN
<sentencias>
END <terminador>

ALTER es el mtodo de ms bajo imparto para cambiar un procedimiento ya que, si ho hay


dependencias que se vean afectadas, se puede ejecutar sin problemas. Para que se pueda ejecutar debe
existir previamente el procedimiento.

RECREATE es idntico a CREATE con la adiccin de que previamente hace un DROP


PROCEDURE. En este caso se producirn excepciones si existen dependencias (no se puede borrar el
objeto si antes no se eliminan las dependencias).

CREATE OR ALTER crea un procedimiento si no existe. Si ya existe ejecuta una operacin


ALTER.

Un procedimiento se borra mediante DROP PROCEDURE procedimiento. Un procedimiento


slo lo puede borrar el usuario SYSDBA o el propietario del procedimiento. Adems, para que se
pueda realizar, no puede estar siendo usado en ninguna transaccin ni tener dependencias en otros
objetos de la base de datos. Si el procedimiento es recursivo se necesita borrar en primer lugar la
llamada a s mismo.

Vicente Tejero Trueba Pag 12 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

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.

Un trigger se puede ejecutar en una de dos fases relativas a la ejecucin de la peticin de


cambio realizada: antes (befote) de escribir o despus (alter). En un trigger es posible definir esta fase
en relacin a un evento (insercin, actualizacin o borrado) o a varios de ellos.

En resumen tenemos que:

Tipo trigger Descripcin


BEFORE INSERT Se lanza antes de que se cree una nueva fila. Permite que se puedan
cambiar los valores de entrada
AFTER INSERT Se dispara despus de que se cree una nueva versin del registro. No se
permite cambiar los valores de entrada. Normalmente se usa para
modificar otras tablas
BEFORE UPDATE Se dispara antes de que se cree una nueva versin del registro. Se permiten
cambios en los valores de entrada
AFTER UPDATE Se lanza despus de que se cree una nueva versin del registro. No se
permiten cambios en los valores de entrada. Normalmente se usa para
modificar otras tablas
BEFORE DELETE Se lanza antes de que una fila existente se borre. No acepta cambios a
ninguna columna en la fila.
AFTER DELETE Se dispara despus de que una fila es borrada. Nose aceptan cambios a
ninguna columna en la fila . Normalmente se usa para modificar otras
tablas.
BEFORE <evento> OR Se dispara antes de que se ejecute cualquier cambio en el estado del dato.
<evento> [OR Se codifican las acciones de forma condicional. Se pueden hacer cambios
<evento>] en las columnas de la fila afectada salvo que sea una accin de borrado
AFTER <evento> OR Se dispara despus de que se ejecute cualquier cambio en el estado del
<evento> [OR dato. Se codifican las acciones de forma condicional. No se pueden hacer
<evento>] cambios de la fila afectada.

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.

Un trigger se crea mediante la sentencia CREATE TRIGGER:

CREATE TRIGGER nombre FOR {tabla | vista}


[ACTIVE | INACTIVE ]

Vicente Tejero Trueba Pag 13 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

{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.

CREATE TRIGGER BI_BANCOS


FOR BANCOS
BEFORE INSERT
AS
BEGIN
new.nom_banco=upper(new.nom_banco); -- pasamos a maysculas el nombre de banco
END

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:

CREATE TRIGGER BI_BANCOS


FOR BANCOS
BEFORE INSERT
AS
BEGIN
IF (new.cod_banco is null) then si no se ha indicado un cod_banco
new.cod banco=gen_id(gen_cod_banco,1); --se recoge el cod_banco del generador
END

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:

{{CREATE TRIGGER nombre}


| {CREATE OR ALTER TRIGGER nombre FOR {tabla | vista}}}
[ACTIVE | INACTIVE ]
{BEFORE |AFTER }
{{DELETE | INSERT | UPDATE }
..

Vicente Tejero Trueba Pag 14 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

Los triggers se borran mediante la sentencia DROP TRIGGER nombre;

Vicente Tejero Trueba Pag 15 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6

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.

Una excepcin puede ocurrir por:


- Error SQL: Mensajes SQL con cdigo negativo de SQLCODE. Adems se tienen otros
cdigos SQLCODE que no representan error como el 0 (ejecutado correctamente) o el 100
(detectado fin de fichero).
- Errores internos de Firebird: Tienen que ver con concurrencia, datos, metadatos y
condiciones del entorno. Tienen un cdigo de error de nueve dgitos, normalmente
empezando por 3355, que identifica de forma nica el GDSCODE. Un mismo SQLCODE
puede ser descompuesto en varios GDSCODE de forma que te ltimo nos da una
informacin mas precisa sobre el error producido. Cuando ocurre una excepcin se pueden
trabajar muchas veces con ambos: SQLCODE y GDSCODE. Por ejemplo podramos tener
el GDSCODE 335544747 usrname_too_long, el 335544768 password_too_long,
335544749 usrname_required, etc , todos bajo el mismo SQLCODE, el -85.
- Excepciones de usuario: Son objetos creados en la base de datos y que se invocan cuando
se cumple una condicin determinada.

Como se ve , una excepcin no es ms que un mensaje que se genera cuando se produce un


error. Todas las excepciones predefinidas (SQLCODE y GDSCODE) tiene mensajes de texto
asociados.

Una excepcin definida por el usuario se crea mediante CREATE EXCEPTION.

CREATE EXCEPTION <nombre> <mensaje>;

En donde nombre es un identificador de cmo mximo 31 caracteres y mensaje una cadena con
conjunto de caracteres NONE. Por ejemplo podramos tener:

CREATE EXCEPTION BANCO_ERRONEO El nombre del banco no vlido;

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

Vicente Tejero Trueba Pag 16 IES Pedro Espinosa


Firebird: SQL Procedimental (PSQL) Tema 6
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.
END ^

Como se ve en este ejemplo, se puede lanzar una excepcin mediante la sentencia


EXCEPTION:

EXCEPTION [<nombre excepcion> [<mensaje en tiempo ejecucin>]]

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:

WHEN {<nombre excepcion> | GDSCODE codigo | SQLCODE codigo | ANY } DO


BEGIN
<sentencias>
END

Mediante la sentencia WHEN se cambia el mecanismo estndar de gestin de errores. Asi


cuando se produce una excepcin se para la ejecucin del bloque en el que se produce. En lugar de
pasar la ejecucin a la sentencia END final, se inicia un procedimiento de bsqueda de una sentencia
WHEN que gestione la excepcin, comenzando por el bloque donde se produjo el error y pasando a
los bloques ms externos. Una vez manejada la excepcin se continua con la ejecucin en la primera
sentencia posterior al bloque de manejo de excepcin ejecutado.

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.

WHEN BANCO_ERRONEO DO capturo la excepcion y la gestiono.


BEGIN
NEW.NOM_BANCO = BANCO || NEW.NOM_BANCO;
END
END ^

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.

Vicente Tejero Trueba Pag 17 IES Pedro Espinosa