Sie sind auf Seite 1von 30

PL/PGSQL

Extensin "procedural" de SQL

Pero primero triggers


DROP TABLE producto cascade; CREATE TABLE producto( id int PRIMARY KEY, vendido timestamp); DROP FUNCTION modificacion() cascade; CREATE FUNCTION modificacion() RETURNS TRIGGER AS ' BEGIN NEW.vendido := ''now''; RETURN NEW; END; 'LANGUAGE 'plpgsql'; DROP TRIGGER t_modificacion on producto; CREATE TRIGGER t_modificacion BEFORE INSERT ON producto FOR EACH ROW EXECUTE PROCEDURE modificacion(); INSERT into producto VALUES (1); SELECT * FROM producto;

6.2

Trigger Layout
BEFORE CREATE TRIGGER <trigger_name> AFTER INSERT UPDATE DELETE OR

OLD NEW
FOR EACH ROW <table_name> FOR EACH STATEMENT

ON

EXECUTE PROCEDURE

<function_name>

<arguments>

);

6.3

Extensiones SQL-99
s Entre las propuestas definidas en el estndar SQL-99

estn la extensin del SQL dotndolo de comandos para controlar el flujo:

5 If, where, loop, etc


s El standard SQL-99 esta bastante lejos de ser

satisfecho por la mayora de las bases de datos.


s Oracle tiene una versin propia de estas extensiones

"procedurales" llamada PL/SQL


s PostgreSQL tiene su versin llamada PL/pgSQL

6.4

Por qu PL/pgSQL
s Permite crear funciones que se ejecutan en el

servidor (versus otras aproximaciones como JDBC que se ejecutan en el cliente con "overhead" de comunicaciones).
s La propia base de datos se encarga de compilar y

gestionar estas funciones con lo que suelen ser eficientes.


s proporciona:
5 variables 5 bucles 5 evaluacin condicional

6.5

Un paso previo a usar PL/pgSQL


s Cuando se crea una base de datos nueva hace falta "autorizar"

el uso de pl/pgSQL (a menos que template1 ya este autorizada) createdb mydatab createlang plpgsql mydatab
s En los laboratorios debera estar "autorizado" por defecto

s Ojo: no se comprueba la sintaxis de las funciones hasta que no

son ejecutadas. (Es difcil depurar el cdigo)

6.6

PL/pgSQL: Estructura de las funciones


s PL/pgSQL presenta una estructura en "Bloques". s Cada bloque se define usando

DECLARE --variables inicializada con NULL cada vez --que se entra en el bloque [...] BEGIN --comandos; [...] END;
s No se pueden definir transacciones dentro de una funcin

6.7

PL/pgSQL estructura
CREATE FUNCTION nombre_funcin (argumentos) RETURNS type AS ' DECLARE declaracion; [...] BEGIN statement; [...] END; ' LANGUAGE 'plpgsql';
s Una funcin puede constar de varios bloques y estos pueden

--variables

--comandos

estar anidados
6.8

PL/pgSQL: Generalidades
s Los tipos de datos pasados a la funcin se dan en parntesis

(sin nombre de variable antes de postgres 8)


s El cuerpo de la funcin se pasa a la base de datos como una

cadena de caracteres (ntese, que el cuerpo empieza y acaba con comillas simples) (escape doble)
s Tras la cadena el lenguaje usado para crear la funcin se define

usando la orden "LANGUAJE" (otros lenguajes posibles son PL/PERL, PL/TCL, C, etc)

6.9

Ejemplo trivial sin pasar parmetros


s Qu hace esta funcin?

CREATE OR REPLACE FUNCTION una_funcion () RETURNS int4 AS ' DECLARE an_integer int4; --variables BEGIN an_integer := 10 * 10; --comandos RETURN an_integer; END; ' LANGUAGE 'plpgsql'; ____________________________
select una_funcion(); una_funcion -----------100 (1 row)
6.10

Tipos de Variables-I
s

Ejemplos de variables:

id_usuario INTEGER; cantidad NUMERIC(5,2); url VARCHAR; -- Mas sobre los tipos siguientes ms adelante micampo mitabla.campo%TYPE; mitupla mitabla%ROWTYPE;
s The general syntax of a variable declaration is:

name [ CONSTANT ] type [ NOT NULL ] [ { DEFAULT | := } expression ];

6.11

Tipos de Variables II
s Todos los tipos de variable definidos para SQL son vlidos en

PL/pgSQL
s No es imprescindible conocer el tipo de variables de los atributos

5 Ejemplos usando %TYPE

DECLARE BEGIN

mivar payroll.salario%TYPE; RETURN mivar*2;

5 %ROWTYPE reserva sitio para toda la tupla 5 Reteniendo la estructura de los datos

DECLARE

mivar payroll%ROWTYPE;

BEGIN RETURN mivar.salario*2;

6.12

Ejemplo trivial pasando variables


CREATE OR REPLACE FUNCTION cal_longitud (text) RETURNS int4 AS ' DECLARE intext ALIAS FOR $1; --primer parametro resultado int4; BEGIN resultado := (SELECT LENGTH(intext)); RETURN resultado; END; ' LANGUAGE 'plpgsql'; ____________________________
SELECT cal_longitud('qwerty'); cal_longitud -------------6 (1 row)
6.13

Ms sobre Variables
s CREATE FUNCTION mifuncion(INTEGER, CHAR, ) s Se pueden pasar hasta 16 variables

5 $1, $2, , $16


s ALIAS permite renombrar variables

CREATE FUNCTION cal_longitud (text) RETURNS int4 AS ' DECLARE intext ALIAS FOR $1; --primer parametro resultado int4; . . .

6.14

Ejemplo usando Rowtype


CREATE OR REPLACE FUNCTION trae_pelicula (integer) RETURNS text AS ' DECLARE pelicula_id ALIAS FOR $1; encontrada_pelicula pelicula%ROWTYPE; BEGIN SELECT INTO encontrada_pelicula * FROM pelicula WHERE id = pelicula_id; RETURN encontrada_pelicula.titulo || '' encontrada_pelicula.agno || '')''; END; ' LANGUAGE 'plpgsql'; s Nota: Si SELECT INTO devuelve ms de una tupla se ignoran ('' ||

todas menos la primera (la solucin a esto ms tarde)

6.15

Ejercicio
s En la base de datos de pelculas crear dos funciones que nos

sirvan para llenar la tabla reparto, dando el nombre de la pelicula y el nombre del actor
CREATE TABLE PELICULA( ID INTEGER, -- Identificador nico TITULO CHAR(70), -- Titulo de la pelcula AGNO DECIMAL(4), -- Ao de estreno PUNTUACION FLOAT, -- Puntuacin media VOTOS INTEGER, -- Numero de votos PRIMARY KEY (ID)); -CREATE TABLE ACTOR ( ID INTEGER, -- Identificador nico NOMBRE CHAR(35), -- Nombre del actor/actriz PRIMARY KEY (ID)); -CREATE TABLE REPARTO( PELICULA_ID INTEGER, -- referencia a la tabla PELICULA ACTOR_ID INTEGER, -- referencia a la tabla ACTOR_ID ORD INTEGER, -- Orden en el reparto -- La estrella es 1, ... -FOREIGN KEY (PELICULA_ID ) REFERENCES PELICULA(ID), FOREIGN KEY (ACTOR_ID) REFERENCES ACTOR(ID), PRIMARY KEY (PELICULA_ID, ACTOR_ID));

6.16

Control de Flujo
s Los programas no suelen ejecutarse de principio a fin sin

exceptuar ninguna lnea de cdigo. PL/pgSQL contiene estructuras de control que permiten seleccionar las lneas de cdigo que sern ejecutarse en tiempo real.
s IFTHENELSEELSE IF

5 ejecucin condicional
s LOOPS, WHILE LOOPS, FOR LOOPS

5 iteraciones 5 bucles

6.17

Ejemplo IF/ELSE
s Programa que calcula la longitud de dos cadenas y devuelve la

longitud mayor. CREATE OR REPLACE FUNCTION cadena_mas_larga(text, text) RETURNS int4 AS ' DECLARE in_uno ALIAS FOR $1; in_dos ALIAS FOR $2; lon_uno int4; lon_dos int4; result int4; BEGIN lon_uno := (SELECT LENGTH(in_uno)); lon_dos := (SELECT LENGTH(in_dos)); IF lon_uno > lon_dos THEN RETURN lon_uno; ELSE RETURN lon_dos; END IF; END; 'LANGUAGE 'plpgsql'; s NOTA 1: se pueden hacer condiciones mas complicadas usando OR y AND s NOTA 2: Como PL/pgSQL se agrupa en bloques no hacen falta parntesis en torno a IF
6.18

Ejemplo bucle WHILE

(FOR)

s Funcin que cuenta cuantas veces aparece un carcter en una cadena

CREATE OR REPLACE FUNCTION cuentac(text,text) RETURNS INT4 AS ' DECLARE intext ALIAS FOR $1; inchar ALIAS FOR $2; lon int4; resultado int4; i int4; tmp char; BEGIN lon := length(intext)+1; i:=1; resultado:=0; WHILE i <= lon LOOP tmp := substr(intext,i,1); IF tmp = inchar THEN resultado := resultado +1; END IF; i:=i+1; END LOOP; RETURN resultado; END ' LANGUAGE 'plpgsql'; -- SELECT cuentac('qwertytq','q');
6.19

Excepciones
s RAISE se usa para imprimir mensajes y, en el caso de

excepcion, abortar la transaccin


s RAISE { NOTICE | EXCEPTION} s RAISE NOTICE

5 RAISE NOTICE ' No hagas eso!' '; 5 RAISE NOTICE ' 'El seor' ' || id || ' 'no est en casa' '; 5 RAISE NOTICE ' 'el seor % no est en casa' ' , id;

6.20

Excepciones: Ejemplo
Calcular la suma de los enteros de n a m (usar la formula (p+1)*p/2 CREATE OR REPLACE FUNCTION suma(int4, int4) RETURNS int4 AS ' DECLARE inicio ALIAS FOR $1; fin ALIAS FOR $2; resultado int; BEGIN IF (inicio <1) THEN RAISE EXCEPTION ''inicio debe ser mayor que 1''; ELSE IF(inicio <= fin) THEN resultado := (fin+1)*fin/2 (inicio-1)*inicio/2; ELSE RAISE EXCEPTION ''El valor inicial % debe ser menor que el final %'', inicio, fin; END IF; END IF; RETURN resultado; END ' LANGUAGE 'plpgsql'; SELECT suma(1,3); $$
s

6.21

SELECT y Bucles
CREATE OR REPLACE FUNCTION trae_pelicula (integer) RETURNS text AS ' DECLARE pelicula_id ALIAS FOR $1; encontrada_pelicula pelicula%ROWTYPE; BEGIN SELECT INTO encontrada_pelicula * FROM pelicula WHERE id = pelicula_id; RETURN encontrada_pelicula.titulo || '' encontrada_pelicula.agno || '')''; ('' ||

s Nota: Si SELECT INTO devuelve ms de una tupla se ignoran

todas menos la primera (la solucin a esto ms tarde)

6.22

SELECT y Bucles
Cuantas tuplas empiezan con una letra determinada CREATE OR REPLACE FUNCTION cuenta_letra (text) RETURNS int4 AS ' DECLARE caracter ALIAS FOR $1; temporal record; tmp_caracter text; resultado int4; BEGIN resultado:=0; FOR temporal IN SELECT titulo FROM pelicula LOOP tmp_caracter :=substr(temporal.titulo,1,1); IF tmp_caracter = caracter THEN resultado := resultado +1; END IF; END LOOP; RETURN resultado; END; 'LANGUAGE 'plpgsql'; SELECT cuenta_letra('A');
s

6.23

Examen Parcial Nov


PUJA

Persona Puja

Puja Objeto

PERSONA

OBJETO

Subastado por Rechazar pujas no admisibles 10% menos que puja anterior Un da ms tarde
6.24

Actualizar campos redundantes vendido

TABLAS
CREATE TABLE persona( id SERIAL, --identificador unico PRIMARY KEY(id) ); CREATE TABLE objeto( id SERIAL, --identificador unico persona_id INT, fecha_salida TIMESTAMP DEFAULT now(), vendido int DEFAULT 0, -- 1 vendido, 0 no vendido precio_salida NUMERIC(10,2), PRIMARY KEY(id), FOREIGN KEY (persona_id) REFERENCES persona(id) ); CREATE TABLE puja( objeto_id INT, persona_id INT, fecha TIMESTAMP, cuantia NUMERIC(10,2), FOREIGN KEY (objeto_id) REFERENCES objeto(id), FOREIGN KEY (persona_id) REFERENCES persona(id), PRIMARY KEY(persona_id,objeto_id,fecha) );
6.25

DATOS
--poblar la tabla ---persona (id) -INSERT INTO persona VALUES (1);-INSERT INTO persona VALUES (2);-INSERT INTO persona VALUES (3);-INSERT INTO persona VALUES (4);-INSERT INTO persona VALUES (5);----objeto(id, persona_id,fecha_salida,vendido,precio_salida) -INSERT INTO objeto VALUES (1,1,now(),DEFAULT,23);-INSERT INTO objeto VALUES (2,1,now()+'-1.1 day',DEFAULT,23); INSERT INTO objeto VALUES (3,3,now()+'-3.14 day',DEFAULT,23); INSERT INTO objeto VALUES (4,3,now()+'-2.9 day',DEFAULT,23); INSERT INTO objeto VALUES (5,3,now()+'-5.9 day',DEFAULT,23); INSERT INTO objeto VALUES (6,4,now()+'-5.9 day',DEFAULT,23); INSERT INTO objeto VALUES (7,4,now()+'-0.9 day',DEFAULT,23); INSERT INTO objeto VALUES (8,5,now()+'-0.8 day',DEFAULT,23); INSERT INTO objeto VALUES (9,5,now()+'-1.34 day',DEFAULT,23); INSERT INTO objeto VALUES (10,5,now()+'-5.9 day',DEFAULT,23); ---puja (objeto_id,persona_id,fecha) -INSERT INTO puja VALUES (1,1,now()+'1 hour',10.34); INSERT INTO puja VALUES (1,1,now()+'2 hour',10.34); INSERT INTO puja VALUES (1,1,now()+'3 hour',10.34); INSERT INTO puja VALUES (1,1,now()+'4 hour',10.34); INSERT INTO puja VALUES (1,1,now()+'5 hour',10.34); INSERT INTO puja VALUES (1,1,now()+'10 hour',10.34); INSERT INTO puja VALUES (10,1,now()+'1 hour',10.34); INSERT INTO puja VALUES (9,1,now()+'1 hour',10.34);

6.26

Ejemplo funcin en C

Ejemplo de Funcin en C
s Cdigo

#include "postgres.h" #include <string.h> /* by value */ int add_one(int arg) { return arg + 1; } s Compilacin gcc -fpic -c foo.c -I /usr/include/pgsql/server/ gcc -shared -o foo.so foo.o

6.28

Ejemplo de Funcin en C-II


s Instalacion: 5 como istrador de la base (postges):

CREATE FUNCTION add_one(integer) RETURNS integer AS '/tmp/foo.so', 'add_one' LANGUAGE C STRICT; _______________________________
s add_one.so es la librera dinmica con la funcin s Ms informacin en: s Recordar que C no soporta todos los tipos usados

http://developer.postgresql.org/docs/postgres/xfunc-c. en SQL (y viceversa)

6.29

Se acab