Trabajando Con Store Procedures PL/PGSQL en PostgreSQL
Trabajando Con Store Procedures PL/PGSQL en PostgreSQL
Trabajando Con Store Procedures PL/PGSQL en PostgreSQL
Los lenguajes de procedimientos (procedural languages) han extendido la funcionalidad de las bases de
datos proporcionando al lenguaje SQL cierto flujo de control similar al de un lenguaje de
programacin.
Cada fabricante tiene su propia implementacin de un lenguaje de procedimiento basado en SQL, as
Microsoft SQL Server tiene Transact-SQL, Oracle tiene PL/SQL y as sucesivamente una lista de
bases de datos con su correspondiente lenguaje de procedimiento. En el caso de PostgreSQL se tienen
varios lenguajes que pueden usarse como lenguajes de procedimiento entre ellos tenemos a PL/Tcl,
PL/Perl, PL/Python,C y como opcin predeterminada PL/pgSQL.
Las ventajas de ejecutar funciones del lado del servidor o Store Procedures con PL/pgSQL son las
siguientes:
1. Extensibilidad: PL/pgsql es como un lenguaje de programacin incluye la asignacin y
evaluacin de variables y la posibilidad de hacer iteraciones y clculos ms complejos que con
SQL.
2. Seguridad: Ayuda a evitar ciertos ataques con SQL Injection ya que al utilizar parmetros evita
la construccin de comandos SQL utilizando la concatenacin de cadenas.
3. Rapidez: Son ejecutados ms rpidamente que las consultas SQL individuales ya que despus
de la primera ejecucin el plan de ejecucin se mantiene en memoria y el cdigo no tiene que
ser analizado ni optimizado nuevamente.
4. Programacin modular: similar a los procedimientos y funciones en los lenguajes de
programacin, lo que evita que se tengan planas de sentencias SQL.
5. Reutilizacin: de cdigo una funcin puede ejecutarse dentro de distintos Store Procedures.
6. Rendimiento: un Store Procedure puede contener decenas de sentencias SQL que son
ejecutadas como una sola unidad de golpe, a diferencia de las sentencias SQL individuales
donde hay que esperar a que cada una sea procesada.
Mediante los siguientes ejemplos mostraremos el uso de Store Procedures utilizando PL/pgSQL.
Creamos una base de datos de ejemplo llamada Catalogs con el siguiente comando desde el Shell.
$ createdb Catalogs
Revisamos los lenguajes de procedimiento instalados en la base de datos, revisamos que PL/pgSQL se
encuentre instalado con el siguiente comando.
$ createlang -l Catalogs
Si no se encuentra, entonces ejecutamos el siguiente comando para instalarlo, esto siempre como
administrador del servidor:
$ createlang U postgres plpgsql Catalogs
Si est instalado entonces abrimos un editor de texto y creamos un archivo llamado catalogs.sql donde
escribiremos los comandos para crear las tablas de ejemplo y los Store Procedures para administrar los
registros de cada una de las tablas.
Para la creacin de las tablas escribimos lo siguiente:
CREATE TABLE Countries(
idcountry char(3) NOT NULL PRIMARY KEY
,name varchar(250) NOT NULL
,created timestamp DEFAULT NOW() NOT NULL
);
CREATE TABLE States(
idstate serial NOT NULL PRIMARY KEY
,name varchar(250) NOT NULL
,idcountry varchar(3) NOT NULL REFERENCES Countries(idcountry)
,created timestamp DEFAULT NOW() NOT NULL
);
CREATE TABLE Cities(
idcity serial NOT NULL PRIMARY KEY
,name varchar(250) NOT NULL
,idstate int NOT NULL REFERENCES States(idstate)
,created timestamp DEFAULT NOW() NOT NULL
);
En acuerdo con la llave fornea definida en cada tabla, debe existir un pas para poder crear un estado,
as mismo debe de existir un estado para poder crear una ciudad, entonces creamos unos registros en la
tabla pases
INSERT
INSERT
INSERT
INSERT
INTO
INTO
INTO
INTO
Countries(idcountry,name)VALUES('arg','argentina');
Countries(idcountry,name)VALUES('bra','brasil');
Countries(idcountry,name)VALUES('ury','uruguay');
Countries(idcountry,name)VALUES('mex','mxico');
Supongamos que estas tablas van a utilizarse en un sistema donde sea obligatorio que los nombres de
pas, estado y ciudad, se almacenen teniendo la primera letra mayscula o en notacin Camel Case,(en
este caso los pases quedaron guardados con letras minsculas de manera intencional, con el fin de
mostrar un Store Procedure).
Creamos entonces una funcin para aplicar esta regla a los datos de la tabla countries.
La funcin se define con el siguiente cdigo:
CREATE FUNCTION UpperCamelCase(varchar) RETURNS varchar AS
'DECLARE
res varchar;
BEGIN
SELECT INTO res UPPER(SUBSTRING($1,1,1)) || LOWER(SUBSTRING($1,2));
return res;
END;'
LANGUAGE 'plpgsql';
Una vez creada en el servidor se encuentra disponible para cualquier transformacin que queramos
aplicar sobre cualquier cadena.
Ahora escribiremos las funciones para insertar registros en cada una de las tablas.
CREATE FUNCTION InsertState(varchar,varchar) RETURNS int AS
'DECLARE
regs record;
res numeric;
BEGIN
SELECT INTO regs count(name) FROM States WHERE name = UpperCamelCase($1);
IF regs.count = 0
THEN
INSERT INTO States(name,idcountry)VALUES(UpperCamelCase($1),$2);
SELECT INTO res idstate FROM States WHERE name = UpperCamelCase($1);
RETURN res;
END IF;
IF regs.count > 0
THEN
SELECT INTO res idstate FROM States WHERE name = UpperCamelCase($1);
RETURN res;
END IF;
END;
' LANGUAGE 'plpgsql';
CREATE FUNCTION InsertCity (varchar,numeric) RETURNS int AS
'DECLARE
regs record;
res numeric;
BEGIN
SELECT INTO regs count(name) FROM Cities WHERE name = UpperCamelCase($1);
IF regs.count = 0
THEN
INSERT INTO Cities(name,idstate)VALUES(UpperCamelCase($1),$2);
SELECT INTO res idcity FROM Cities WHERE name = UpperCamelCase($1);
RETURN res;
END IF;
IF regs.count > 0
THEN
SELECT INTO res idcity FROM Cities WHERE name = UpperCamelCase($1);
RETURN res;
END IF;
END;
' LANGUAGE 'plpgsql';
Vemos que en cada Store Procedure, reutiliza la funcin UpperCamelCase(varchar) que habamos
previamente creado.
Esto porque un Store Procedure puede llamar a otro Store Procedure que se encuentre disponible.
En las siguientes imgenes los resultados de la ejecucin de cada Store Procedure.