Está en la página 1de 28

PL/pgSQL - SQL Procedural Language

Traduccin: Adolfo Pachn (Proyecto S.O.B.L.)

Sinopsis:
Esta es la primera re isin de la traduccin del cap!tulo "# de la o$ra %%Post&reS'L (.)de el *ocumentation++, creada por el The PostgreSQL Global Development Group.

Contenido

1 Introduccin

Los objetivos de diseo para PL/pgSQL fueron crear un lenguaje procedural cargable que

pudiera ser usado para crear funciones ytriggers, aadiera estructuras de control al lenguaje SQL, pudiera realizar computaciones complejas, heredase todos los tipos definidos por el usuario, funciones y operadores, pudiera ser definido para ser validado por el servidor, fuese sencillo de utilizar

!l manejador de llamadas PL/pgSQL interpreta la el c"digo fuente en te#to plano de la funci"n y produce un $rbol de instrucciones binarias internas la primera vez que %sta es llamada &dentro de cualquier proceso principal' !l $rbol de instrucciones traduce toda la estructura del estamento PL/pgSQL, pero las e#presiones individuales de SQL y las consultas SQL usadas en la funci"n no son traducidas inmediatamente
(omo cada e#presi"n y consulta SQL es usada primero en la funci"n, el int%rprete PL/pgSQL crea un plan de ejecuci"n preparado &usando las funciones del gestor SP) SPI_prepare y SPI_saveplan' Las siguientes visitas a dicha e#presi"n o consulta reutilizar en plan preparado *s+, una funci"n con c"digo condicional que contiene muchos estamentos para los cuales el plan de ejecuci"n podr+a ser requerido s"lo preparar$ y almacenar$ aquellos planes que realmente sean usados durante el tiempo de vida de la cone#i"n a la base de datos !sto puede consecuentemente reducir la cantidad de tiempo requerida para interpretar y generar planes de consultas para los estamentos en una funci"n de lenguaje procedural ,na desventaja es que los errores en una e#presi"n o consulta espec+fica puede no ser detectada hasta que no se llegue a esa parte de la funci"n en la ejecuci"n ,na vez que PL/pgSQL ha realizado un plan de consulta para una determinada consulta en una funci"n, %ste reusar$ dicho plan durante toda la vida de la cone#i"n a la base de datos !sto significa normalmente una ganancia en el rendimiento, pero puede causar algunos problemas si usted altera din$micamente su esquema de base de datos Por ejemploCREATE FUNCTION populate() RETURNS INTEGER AS ' DECLARE -- Declarations EGIN !ERFOR" #$%&unction()' END' ' LANGUAGE 'plp(s)l'' Si usted ejecuta la funci"n anterior, %sta referenciar$ el .)/ para my_function() en el plan de consulta producido para el estamento P!01.02 2$s tarde, si useted elimina y vuelve a crear la funci"n my_function(), entonces populate() no ser$ capaz de encontrar la funci"n my_function() nunca m$s ,sted deber+a crear de nuevo populate(), o iniciar una nueva sesi"n de bases de datos para que se realice una nueva compilaci"n /ebido a que PL/pgSQL almacena los planes de ejecuci"n de esta forma, las consultas que aparezcan directamente en una funci"n PL/pgSQL se deben referir a las mismas tablas y campos en cada ejecuci"n3 es decir, no puede usar un par$metro como el nombre de una tabla o campo en una consulta Para evitar

esta restricci"n, puede construir consultas din$micas usando el estamente de PL/pgSQL !4!(,5! 6al coste de construir un nuevo plan de consultas en cada ejecuci"n6

NOTA- !l estamento !4!(,5! de PL/pgSQL no est$ relacionado con el estamento !4!(,5! soportado por el motor PostgreSQL !l estamento del motor no puede ser usado dentro de funciones PL/pgSQL &y no es necesario hacerlo' !#cepto para el caso de conversi"n de entrada/salida y funciones de c$lculo para tipos definidos por el usuario, cualquier cosa que pueda ser definida en funciones del lenguaje ( tambi%n pueden serlo con PL/pgSQL !s posible crear complejas funciones de computaci"n condicionales y m$s tarde usarlas para definir operadores u usarlas en +ndices funcionales

1.1 Ventajas de usar PL/p S!L

1.1.1 Mayor Rendimiento


SQL es el lenguaje que PostgreSQL &y la mayor+a del resto de bases de datos relacionales' usa como lenguaje de consultas !s portable y f$cil de aprender Pero cada estamento SQL debe ser ejecutado individualmente por el servidor de bases de datos !sto significa que su aplicaci"n cliente debe enviar cada consulta al servidor de bases de datos, esperar a que se procese, recibir el resultado, realizar alguna computaci"n, y luego enviar otras consultas al servidor 5odo esto incurre en una comunicaci"n entre procesos y tambi%n puede sobrecargar la red si su cliente se encuentra en una m$quina distinta al servidor de bases de datos (on PL/pgSQL puede agrupar un grupo de computaciones y una serie de consultas dentro del servidor de bases de datos, teniendo as+ la potencia de un lenguaje procedural y la sencilllez de uso del SQL, pero ahorrando una gran cantidad de tiempo porque no tiene la sobrecarga de una comunicaci"n cliente/servidor !sto puede redundar en un considerable aumento del rendimiento

1.1.2 Soporte SQL


PL/pgSQL aade a la potencia de un lenguaje procedural la fle#ibilidad y sencillez del SQL (on PL/pgSQL puede usar todos los tipos de datos, columnas, operadores y funciones de SQL

1.1.3 Portabilidad
/ebido a que las funciones PL/pgSQL corren dentro de PostgreSQL, estas funciones funcnionar$n en cualquier plataforma donde PostgreSQL corra *s+ podr$ reusar el c"digo y reducir costes de desarrollo

1.2 Desarrollando en PL/pgSQL


/esarrollar en PL/pgSQL es agradable y r$pido, especialmente si ya ha desarrollado con otros lenguajes procedurales de bases de datos, tales como el PL/SQL de .racle /os buenas formas de desarrollar en PL/pgSQL son-

,sar un editor de te#to y recargar el archivo con ps"l ,sando la herramienta de usuario de PostgreSQL- P #ccess

,na buena forma de desarrollar en PL/pgSQL es simplemente usar el editor de te#tos de su elecci"n y, en otra ventana, usar ps"l &monitor interactivo de PostgreSQL' para cargar las funciones Si lo est$ haciendo de %sta forma, es una buena idea escribir la funci"n usando (0!*5! .0 0!PL*(! 1,7(5).7 /e esta forma puede recargar el archivo para actualizar la definici"n de la funci"n Por ejemploCREATE OR RE!LACE FUNCTION test&unc(INTEGER) RETURNS INTEGER AS ' **** en+' ' LANGUAGE 'plp(s)l'' 2ientras corre ps"l, puede cargar o recargar la definici"n de dicha funci"n con

,i &ilena#e*s)l y luego inmediatamente utilizar comandos SQL para testear la funci"n .tra buena forma de desarrollar en PL/pgSQL es usando la herramienta administrativa gr$fica de PostgreSQL- P #ccess !sta hace algunas cosas m$s c"modas para usted, tales como escapar comillas simples, y facilitar la recreaci"n y depuraci"n de funciones

2 Estructura de PL/pgSQL
PL/pgSQL es un lenguaje estructurado de bloques !l te#to completo de una definici"n de funci"n debe ser un bloque ,n bloque se define como- ..eti)ueta// 0 - DECLARE +eclaraciones 0 EGIN esta#entos END' (ualquier estamento en la secci"n de estamentos de un bloque puede ser un subbloque Los subbloques pueden ser utilizados para agrupaciones l"gicas o para lcoalizar variables para un pequeo grupo de estamentos Las variables declaradas en la secci"n de declaraciones que preceden a un bloque son inicializadas a sus valores por defecto cada vez que el bloque es introducido, no s"lo una vez por cada llamada a la funci"n Por ejemploCREATE FUNCTION al(una&uncion() RETURNS INTEGER AS ' DECLARE canti+a+ INTEGER 12 34' EGIN RAISE NOTICE ''La canti+a+ a)u5 es 6''7canti+a+' -- La canti+a+ a)u5 es 34 canti+a+ 12 84' --- Crea un su99lo)ue -DECLARE canti+a+ INTEGER 12 :4' EGIN RAISE NOTICE ''La canti+a+ a)u5 es 6''7canti+a+' -- La canti+a+ a)u5 es :4 END' RAISE NOTICE ''La canti+a+ a)u5 es 6''7canti+a+' -- La canti+a+ a)u5 es 84 RETURN canti+a+' END' ' LANGUAGE 'plp(s)l'' !s importante no confundir el uso de 8!9)7/!7/ para la agrupaci"n de estamentos en PL/pgSQL con los comandos de base de datos para el control de transacciones Los comandos 8!9)7/!7/ de PL/pgSQL son s"lo para agrupar3 ellos no inician o finalizan una transacci"n Los procedimientos de funciones y triggers son siempre ejecutados dentro de una transacci"n establecida por una consulta e#terna 6no pueden iniciar o validar transacciones, ya que PostgreSQL no tiene transacciones anidadas

2.1 Detalles Lxicos


(ada estamento y declaraci"n dentro de un bloque est$ terminado por un punto y coma 5odas las palabras clave e identificadores pueden ser escritos en caracteres may:sculas/min:sculas Los identificadores ser$n impl+citamente convertidos a min:sculas, a menos que est%n entrecomillados &usando para ello comillas dobles' ;ay dos tipos de comentarios en PL/pgSQL ,n gui"n doble 6inicia un comentario que se e#tiende hasta el final de la l+nea6 ,n /< marca el inicio de un bloque de comentarios que se e#tiende hasta la siguente ocurrencia de </ Los bloques de comentarios no pueden anidarse, pero los comentarios con doble

guionado pueden encerrarse en un bloque de comentarios, y un doble gui"n puede ocultar los delimitadores de bloques de comentarios /< y </

3 Declaraciones
5odas las variables, filas y registros usados en un bloque deben estar declaradas en la secci"n de declaraciones del bloque &la :nica e#cepci"n es que la variable de bucle para una iteraci"n de bloque 1.0 sobre un rango de valores enteros es autom$ticamente declarada como variable entera' Las variables PL/pgSQL pueden ser de cualquier tipo de datos SQL, tales como )75!9!0, =*0(;*0 y (;*0 *qu+ tiene algunos ejemplos de declaraci"n de variablesuser%i+ INTEGER' canti+a+ NU"ERIC(8)' url ;ARC<AR' #$ro= no#9reta9la6RO>T?!E' #$&iel+ no#9reta9la*no#9reca#po6T?!E' una&ila RECORD' La sinta#is general de una declaraci"n de variables esno#9re - CONSTANT 0 tipo - NOT NULL 0 - @ DEFAULT A 12 B eCpresiDn 0' La cl$usula /!1*,L5, si e#iste, especifica el valor inicial asignado a la variable cuando el bloque es introducido Sinla cl$usula /!1*,L5 no es facilitada entonces la variable es inicializada al valor SQL 7,LL La opci"n (.7S5*75 previene la asignaci" de otros valores a la variable, as+ que su valor permanece durante la duraci"n del bloque Si se especifica 7.5 7,LL, una asignaci"n de un valor 7,LL resulta en un error en tiempo de ejecuci"n 5odas las variables declaradas como 7.5 7,LL deben tener un valor por defecto no nulo especificado !l valor por defecto es evaluado cada vez que el bloque es introducido *s+, por ejemplo, la asignaci"n de no$ a una variable de tipo timestamp provoca que la variable tenga la fecha y hora de la llamada a la actual funci"n, y no la fecha y hora de su compilaci"n !jemploscanti+a+ INTEGER DEFAULT 3E' url FarcGar 12 ''Gttp1HH===*so9l*or(''' user%i+ CONSTANT INTEGER 12 I4'

3.1 Alias para los Par !etros de la "unci#n


no#r9e ALIAS FOR Jn' Los par$metros pasados a las funciones son nominados con los identificadores >?, >@, etc .pcionalmente, se pueden declara alias para los nombres de los par$metros, con el objeto de incrementar la legibilidad del c"digo 5anto el alias como el identificador num%rico pueden ser utilizados para referirse al valor del par$metro *lgunos ejemplosCREATE FUNCTION tasa%Fentas(REAL) RETURNS REAL AS ' DECLARE su9total ALIAS FOR JI' EGIN return su9total K 4*4L' END' ' LANGUAGE 'plp(s)l'' CREATE FUNCTION instr(;ARC<AR7INTEGER) RETURNS INTEGER AS ' DECLARE F%strin( ALIAS FOR JI' in+eC ALIAS FOR JE' EGIN -- Al(unas co#putaciones a)u5

END' ' LANGUAGE 'plp(s)l'' CREATE FUNCTION usa%#ucGos%ca#pos(ta9lena#e) RETURNS TEMT AS ' DECLARE in%t ALIAS FOR JI' EGIN RETURN in%t*&I AA in%t*&3 AA in%t*&8 AA in%t*&N' END' ' LANGUAGE 'plp(s)l''

3.2 $ipos "ila %&o'(


no#9re no#9reta9la6RO>T?!E' ,na variable de un tipo compuesto es denominada varia%le de fila &ro$&type varia%le' ,na variable de este tipo puede almacenar una fila completa del resultado de una consulta S!L!(5 o 1.0, mientras que la columna de dicha consulta coincida con el tipo declarado para la variable Los campos individuales del valor de la fila son accedidos usando la t+pica notaci"n de puntos, por ejemplo varia%lefila.campo !n la actualidad, una variable de tipo fila s"lo puede ser declarada usando la notaci"n A0.B5CP!3 aunque uno podr+a esperar que un nombre p:blico de de nombre de tabla funcionase como tipo de declaraci"n, %sta no ser+a aceptada dentro de funciones PL/pgSQL Los par$metros para una funci"n pueden ser tipos compuestos &filas completas de tablas' !n ese caso, el correspondiente identificador >n ser$ una variable tipo fila, y los campos podr$n ser accedidos, por ejemplo '1.nom%recampo S"lo los atributos de una tabla definidos por el usuario son accesibles en una variable tipo fila, y no .)/ u otros atributos de sistema &porque la fila podr+a venir de una vista' Los campos del tipo fila heredan el tamao del campo de la tabla as+ como la precisi"n para tipos de datos, tales como c(ar(n) CREATE FUNCTION usa%+os%ta9las(ta9lena#e) RETURNS TEMT AS ' DECLARE in%t ALIAS FOR JI' use%t ta9laEno#9re6RO>T?!E' EGIN SELECT K INTO use%t FRO" ta9laEno#9re ><ERE *** ' RETURN in%t*&I AA use%t*&3 AA in%t*&8 AA use%t*&N' END' ' LANGUAGE 'plp(s)l''

3.3 &ecords
no#9re RECORD' Las variables de tipo re istro &record' son similares a las tipo fila, pero no tienen una estructura predefinida !llas la toman de la actual estructura de la fila que tienen asignada durante un comando S!L!(5 o 1.0 La subestructura de una variable tipo registro puede variar cada vez que se le asigne un valor ,na consecuencia de esto es que hasta que a una variable tipo registro se le asigne valor por vez primera, %sta no tendr$ subestructura, y cualquier intento de acceder a un campo en ella provocar$ un error en tiempo de ejecuci"n *dvierta que 0!(.0/ no es un verdadero tipo de datos, s"lo un almacenador

3.) Atri*utos
,sando los atributos A5CP! y A0.B5CP!, puede declarar variables con el mismo tipo de datos o estructura que otro elemento de la base de datos &p ej- un campo de tabla' Faria9le6T?!E A5CP! proporciona el tipo de datos de una variable o de una columna de base de datos Puede usar esto para declarar variables que almacenen valores de base de datos Por ejemplo, digamos que tiene una columna llamada user_id en su tabla usuarios Para declarar una variable con el mismo tipo de datos que usuarios userDid usted escribir+auser%i+ usuarios*user%i+6T?!E'

,sando A5CP! no necesita conocer el tipo de datos de la estructura a la que est$ referenciando, y lo m$s importante, si el tipo de datos del elemento referenciado cambia en el futuro &p ej - usted cambia su definici"n de tabla para user_id de )75!9!0 a 0!*L', no necesitar$ cambiar su definici"n de funci"n ta9la6RO>T?!E A0.B5CP! proporciona el tipo de datos compuesto correspondiente a toda la fila de la tabla especificada La tabla debe ser una tabla e#istente o un nombre de vista de la base de datos DECLARE users%rec usuarios6RO>T?!E' user%i+ usuarios*user%i+6T?!E' EGIN user%i+ 12 users%rec*user%i+' *** CREATE FUNCTION +oes%Fie=%eCist(INTEGER) RETURNS 9ool AS ' DECLARE Oe$ ALIAS FOR JI' ta9le%+ata cs%#aterialiPe+%Fie=s6RO>T?!E' EGIN SELECT INTO ta9le%+ata K FRO" cs%#aterialiPe+%Fie=s ><ERE sort%Oe$2Oe$' IF NOT FOUND T<EN RETURN &alse' END IF' RETURN true' END' ' LANGUAGE 'plp(s)l''

3.+ &,-A.,
RENA"E ol+na#e TO ne=na#e' ,sando la declaraci"n 0!7*2! puede cambiar el nombre de una variable, registro o fila !sto es inicialmente :til si 7!B o .L/ debieran ser referenciados por otro nombre dentro de un procedimiento trigger =ea tambi%n *L)*S !jemplosRENA"E i+ TO user%i+' RENA"E tGis%Far TO tGat%Far'

NOTA- 0!7*2! parece que no funciona en PostgreSQL E F *rreglar esto es poco prioritario, ya que *L)*S cubre la mayor+a de los usos pr$cticos de 0!7*2!

E!presiones
5odas las e#presiones utilizadas en los estamentos PL/pgSQL son procesados usando el ejecutor SQL regular del servidor Las e#presiones que parecen contener constantes pueden de hecho requerir evaluaci"n en tiempo de ejecuci"n &p ej ))no$** para el tipo timestamp', as+ que es imposible para el int%rprete de PL/pgSQL identificar valores reales de constantes aparte del valor clave 7,LL 5odas las e#presiones son evaluadas internamente al ejecutar la consulta SELECT eCpresiDn usando el gestor SP) !n la e#presi"n, las ocurrencias de identificadores de variables PL/pgSQL son reemplazadas por par$metros, y los actuales valores de las variables son pasados al ejecutor en el array de par$metros !sto permite al plan de consultas para el S!L!(5 que sea preparado s"lo una vez, y luego reutilizado para subsequentes evaluaciones La evaluaci"n realizada por el int%rprete principal de PostgreSQL tiene algunos efectos de cara a la interpretaci"n de valores de constantes !n detalle aqu+ est$ la diferencia entre lo que hacen estas dos funcionesCREATE FUNCTION lo(&uncI (TEMT) RETURNS TI"ESTA"! AS ' DECLARE lo(tCt ALIAS FOR JI'

EGIN INSERT INTO lo(ta9le ;ALUES (lo(tCt7 ''no='')' RETURN ''no=''' END' ' LANGUAGE 'plp(s)l'' y CREATE FUNCTION lo(&uncE (TEMT) RETURNS TI"ESTA"! AS ' DECLARE lo(tCt ALIAS FOR JI' curti#e ti#esta#p' EGIN curti#e 12 ''no=''' INSERT INTO lo(ta9le ;ALUES (lo(tCt7 curti#e)' RETURN curti#e' END' ' LANGUAGE 'plp(s)l'' !n el caso de lo func1(), el int%rprete principal de PostgreSQL sabe cu$ndo preparar el plan para el )7S!05, y la cadena *no$* deber+a ser interpretada como un timestamp debido a que el campo destino de lo ta%le es de ese tipo *s+, crear$ una constante a partir de %l y su valor constante ser$ usado luego en todas las invocaciones de lo func1() durante el tiempo de vida del motor 7o es necesario decir que esto no era lo que deseaba el programador !n el caso de lo func+(), el int%rprete principal de PostgreSQL no sabe a qu% tipo deber+a pertenecer *no$* y por tanto devuelve un valor de tipo te,t conteniendo la cadena *no$* /urante la siguiente asignaci"n a la variable local curtime, el int%rprete de PL/pgSQL casa esta cadena con el tipo timestamp llamando a las funciones te,t_out() y timestamp_in() para la conversi"n *s+, el timestamp computado es actualizado en cada ejecuci"n, tal como esperaba el programador La naturaleza mutable de las variables tipo registro presenta un problema en su cone#i"n (uando los campos de una variable registro son usados en e#presiones o estamentos, los tipos de datos de los campos no debe cambiar entre llamadas de una y la misma e#presi"n, ya que la e#presi"n ser$ planeada usando el tipo de datos que estaba presente cuando la e#presi"n fue analizada por vez primera 0ecuerde esto cuando escriba procedimientos trigger que manejen eventos para m$s de una tabla &!4!(,5! puede ser usado para resolver este problema cuando sea necesario'

" Estamentos #$sicos


!n %sta secci"n y las siguientes subsecciones, describiremos todos los tipos de estamentos e#pl+citamente reconocidos por PL/pgSQL (ualquiera no reconocido como uno de estos tipos de estamentos se presume ser una consulta SQL, y es enviada al motor de la base de datos para ser ejecutado &tras la sustituci"n de cualesquiera variables PL/pgSQL usadas en el estamento' *s+, por ejemplo, los comandos SQL )7S!05, ,P/*5!, y /!L!5! pueden ser considerados para ser estamentos de PL/pgSQL Pero ellos no est$n e#pl+citamente listados aqu+

+.1 Asignaci#n
,na asignaci"n de un valor a una variable o campo de fila/registro se escribei+enti&ica+or 12 eCpresiDn' (omo se e#plic" anteriormente, la e#presi"n en el estamento es evaluada como si de un env+o de comando SQL S!L!(5 al motor se tratara La e#presi"n debe contener un :nico valor Si el tipo de datos resultante de la e#presi"n no coincide con el tipo de datos de la variable, o la variable tiene un determinado tamao/precisi"n &tal como c(ar(+-)', el valor resultante ser$ impl+citamente convertido por el int%rprete PL/pgSQL usando la resultante funci"n de tipos output&function y el tipo de variable input&function *dvierta que esto podr+a potencialmente resultar en errores en tiempo de ejecuci"n generados por la funci"n de entrada, si el formato de la cadena del valor resultante no es aceptable para la funci"n de entrada !jemplosuser%i+ 12 E4' taC 12 su9total K 4*4L'

+.2 S,L,C$ /-$0


!l resultado de un comando S!L!(5 que contiene m:ltiples columnas &pero s"lo una fila' puede ser asignado a una variable tipo registro, tipo fila, o variables escalares o de lista !sto se hace as+SELECT INTO +estino eCpressions FRO" ***' donde destino puede ser una variable registro, fila, o una lista separada por comas de variables simples y campos registro/fila *dvierta que esto es algo diferente a la interpretaci"n normal que hace PostgreSQL del S!L!(5 )75., la cual es que el destino &target' )75. es una tabla reci%n creada &si quiere crear una tabla a partir de un resultado de S!L!(5 dentro de una funci"n PL/pgSQL, use la sinta#is (0!*5! 5*8L! *S S!L!(5' Si una fila o lista de variables es usada como destino, los valores seleccionados deben coincidir e#actamente con la estructura de los destinos, u ocurrir$ un error en tiempo de ejecuci"n (uando una variable tipo registro es el destino, esta autom$ticamente se configurar$ al tipo fila de las columnas resultantes de la consulta !#cepto por la cl$usula )75., el estamento S!L!(5 es igual que el normal de la consulta SQL S!L!(5 y puede usar todo el potencial de S!L!(5 Si la consulta S!L!(5 retorna cero filas, valores nulos son asignados a los destinos Si la consulta S!L!(5 retorna m:ltiples filas, la primera es asignada a los destinos y el resto es descartado &*dvierta que la GGprimera filaHH depender$ del uso de .0/!0 8C ' *ctualmente, la cl$usula )75. puede aparecer en cualquier lugar en la cl$usula S!L!(5, pero se recomienda ubicarla inmediatamante despu%s de la palabra clave S!L!(5 1uturas versiones de PL/pgSQL pueden ser menos restrictivas sobre esto Puede usar 1.,7/ immediatamente despu%s de un estamento S!L!(5 )75. para determinar si la asignaci"n tuvo %#ito &es decir, al menos una fila fue retornada por el estamento S!L!(5' Por ejemploSELECT INTO #$rec K FRO" E"! ><ERE e#pna#e 2 #$na#e' IF NOT FOUND T<EN RAISE EMCE!TION ''e#plo$ee 6 not &oun+''7 #$na#e' END IF' *lternativamente, puede usar el condicional )S 7,LL &o )S7,LL' para testear si un resultado de 0!(.0//0.B es nulo *dvierta que no hay forma de saber si adicionales filas han sido descartadas DECLARE users%rec RECORD' &ull%na#e FarcGar' EGIN SELECT INTO users%rec K FRO" users ><ERE user%i+23' IF users%rec*Go#epa(e IS NULL T<EN -- user entere+ no Go#epa(e7 return QGttp1HHQ RETURN ''Gttp1HH''' END IF' END'

+.3 ,xecutando una expresi#n o consulta sin resultado


*lgunas veces uno desea evaluar una e#presi"n o consulta pero descartando el resultado &normalmente porque uno est$ llamando a una funci"n que tiene efectos :tiles, pero un resultado in:til' Para hacer esto en PL/pgSQL, use el estamento P!01.02!ERFOR" )uer$' !sto ejecuta una consulta S!L!(5 y descarta el resultado Las variables PL/pgSQL son sustituidas en la consulta de la forma usual *dem$s, la variable especial 1.,7/ se establece a true si la consulta produce al menos una fila, o false si no produce ninguna

NOTA- ,no podr+a esperar que S!L!(5 sin cl$usuala )75. podr+a acompaar al resultado, pero actualmente la :nica forma aceptada para hacerlo es con P!01.02 ,n ejemplo!ERFOR" create%#F(''cs%session%pa(e%re)uests%#F''7 #$%)uer$)'

+.) ,1ecutando Consultas Din !icas


1recuentemente querr$ generar conultas din$micas dentro de sus funciones PL/pgSQL, es decir, consultas que implican a diferentes tablas o distintos tipos de datos cada vez que son ejecutados Los intentos normales de crear planes de consultas de PL/pgSQL no funcionar$n en estos escenarios Para manejar el problema, se proporciona el estamento !4!(,5!EMECUTE )uer$-strin(' donde "uery&strin es una e#presi"n que contiene una cadena &de tipo te,t' conteniendo la consulta a ser ejecutada !sta cadena es le+da literalmente por el motor SQL *dvierta en particular que no se hacen sustituciones de variables PL/pgSQL en la cadena consulta Los valores de las variables deben ser insertados en la cadena en el momento de su construcci"n (uando se trabaja con consultas din$micas tendr$ que realizar el escape de comillas simples en PL/pgSQL =ea la tabla de la secci"n ?? para una e#plicaci"n detallada Le ahorrar$ esfuerzos *l contrario de otras consultas en PL/pgSQL, una consulta ejecutada por un estamento !4!(,5! no es preparada ni almacenada s"lo una vez durante la vida del servidor *l contrario, la consulta es preparada cada vez que se ejecuta el estamento La consulta6cadena puede ser din$micamente creada dentro del procedimiento para realizar acciones sobre tablas y campos Los resultados de consultas S!L!(5 son descartados por !4!(,5!, y S!L!(5 )75. no est$ actualmente soportado dentro de !4!(,5! *s+, la :nica forma de e#traer un resultado de un S!L!(5 creado din$micamente es usar el formato 1.06)76!4!(,5! descrito m$s adelante ,n ejemploEMECUTE ''U!DATE t9l SET '' AA )uote%i+ent(&iel+na#e) AA '' 2 '' AA )uote%literal(ne=Falue) AA '' ><ERE ***''' !ste ejemplo muestra el uso de las funciones "uote_ident(./0.) y "uote_literal(./0.) Las variables conteniendo identificadores de campos y tablas deber+an ser pasadas a la funci"n "uote_ident() Las variables conteniendo elementos literales de la consulta din$mica deber+an ser pasados a la funci"n "uote_literal() *mbas toman los pasos apropiados para retornar el te#to introducido encerrado entre comillas simples o dobles y con cualesquiera caracteres especiales embebidos, debidamente escapados *qu+ tiene un ejemplo m$s largo de una consulta din$mica y !4!(,5!CREATE FUNCTION cs%up+ate%re&errer%t$pe%proc() RETURNS INTEGER AS ' DECLARE re&errer%Oe$s RECORD' -- Declare a (eneric recor+ to 9e use+ in a FOR a%output FarcGar(R444)' EGIN a%output 12 ''CREATE FUNCTION cs%&in+%re&errer%t$pe(FarcGar7FarcGar7FarcGar) RETURNS ;ARC<AR AS '''' DECLARE F%Gost ALIAS FOR JI' F%+o#ain ALIAS FOR JE' F%url ALIAS FOR J3' EGIN ''' --- A+Fierta cD#o escanea#os a traFSs +e los resulta+os para una consulta en un 9ucle FOR -- usan+o el constructor FOR .re(istro/* -FOR re&errer%Oe$s IN SELECT K FRO" cs%re&errer%Oe$s ORDER ? tr$%or+er LOO! a%output 12 a%output AA '' IF F%'' AA re&errer%Oe$s*Oin+ AA '' LITE '''''''''' AA re&errer%Oe$s*Oe$%strin( AA '''''''''' T<EN RETURN ''''''

AA re&errer%Oe$s*re&errer%t$pe AA ''''''' END IF'''' END LOO!' a%output 12 a%output AA '' RETURN NULL' END' '''' LANGUAGE ''''plp(s)l'''''''' -- Esto &unciona por)ue no esta#os sustitu$en+o Faria9les -- De lo contrario7 &allar5a* ;ea !ERFOR" para otra &or#a +e eUecutar &unciones EMECUTE a%output' END' ' LANGUAGE 'plp(s)l''

+.+ 0*teniendo ,stado de &esultado


;ay varias formas de determinar el efecto de un comando !l primer m%todo es usar 9!5 /)*97.S5)(S, el cual tiene el siguiente formatoGET DIAGNOSTICS Faria9le 2 ite# - 7 *** 0 ' !ste comando permite el retorno de indicadores de estado del sistema (ada elemento es una palabra clave identificando un estado de valor a ser asignado a la variable especificada &que deber+a ser del tipo de datos correcto para recibirlo' Los elementos de estado disponibles actualmente son 0.BD(.,75, el n:mero de filas procesadas por la :ltima consulta SQL enviada al motor SQL3 y 0!S,L5D.)/, el .)/ de la :ltima fila insertada por la m$s reciente consulta SQL *dvierta que 0!S,L5D.)/ s"lo es :til tras una consulta )7S!05 GET DIAGNOSTICS Far%inte(er 2 RO>%COUNT' ;ay una variable especial llamada 1.,7/, de tipo %oolean 1.,7/ se inicializa a false con cada funci"n PL/pgSQL !s valorada por cada uno de los siguientes tipos de estamentos-

,n estamento S!L!(5 )75. establece 1.,7/ a true si %ste retorna una fila, false si no se retorna ninguna ,n estamento P!01.02 establece 1.,7/ a true si produce una fila, false en caso contrario Los estamentos ,P/*5!, )7S!05, y /!L!5! establecen 1.,7/ a true si al menos una fila es afectada, false en caso contrario ,n estamento 1!5(; establece 1.,7/ a true si retorna una fila, false en caso contrario ,n estamento 1.0 establece 1.,7/ a true si %ste itera una o m$s veces, o false en caso contrario !sto se aplica a las tres variantes del estamento 1.0 &bucles 1.0 enteros, bucles de registro, y bucles de registros din$micos' 1.,7/ s"lo se establece cuando el bucle 1.0 termina- dentro de la ejecuci"n del bucle, 1.,7/ no es modificado por el estamento 1.0, aunque puede ser cambiado por la ejecuci"n de otros estamentos dentro del cuerpo del bucle

1.,7/ es una variable local3 cualesquiera cambios afectar$n s"lo a la actual funci"n PL/pgSQL

% Estructuras de &ontrol
Las estructuras de control son probablemente la parte m$s :til &e importante' de PL/pgSQL (on las estructuras de control de PL/pgSQL, puede manipular datos de PostgreSQL de forma fle#ible y potente

2.1 &etornando desde una "unci#n


RETURN eCpression' 0!5,07 con una e#presi"n es usado para retornar desde una funci"n PL/pgSQL que no retorna nada La funci"n termina y el valor de la e#presi"n es retornado al peticionario Para retornar un valor compuesto &una fila', usted debe escribir una variable registro o fila como e#presi"n (uando retorne una tipo escalar, cualquier e#presi"n pude ser usada !l resultado de la e#presi"n ser$ autom$ticamente convertido al tipo de retorno de la funci"n &si ha declarado la funci"n para que retorne void &nulo', entonces la e#presi"n puede ser omitida, y se ignorar$ en cualquier caso'

!l valor de retorno de una funci"n no puede ser dejado sin definir Si el control llega al final del bloque de mayor nivel de la funci"n sin detectar un estamento 0!5,07, ocurrir$ un error en tiempo de ejecuci"n (uando una funci"n PL/pgSQL es declarada para que retorne un S!5.1 de alg:n tipo, el procedimiento a seguir es algo diferente !n ese caso, los elementos individuales a retornar son especificados en comandos 0!5,07 7!45, y luego un comando final 0!5,07 sin argumentos es usado para indicar que la funci"n ha terminado su ejecuci"n 0!5,07 7!45 puede ser usado tanto con tipos de datos escalares como compuestos3 en el :ltimo caso, una GGtablaHH entera de resultados ser$ retornada Las funciones que usen 0!5,07 7!45 deber+an ser llamadas de la siguiente formaSELECT K FRO" so#e%&unc()' !sto es, la funci"n es usada como una tabla de origen en una cl$usula 10.2 RETURN NEMT eCpression' 0!5,07 7!45 does not actually return from the function3 it simply saves aIay the value of the e#pression &or record or roI variable, as appropriate for the data type being returned' !#ecution then continues Iith the ne#t statement in the PL/pgSQL function *s successive 0!5,07 7!45 commands are e#ecuted, the result set is built up * final 0!5,07, Ihich need have no argument, causes control to e#it the function

Note- 5he current implementation of 0!5,07 7!45 for PL/pgSQL stores the entire result set before returning from the function, as discussed above 5hat means that if a PL/pgSQL function produces a very large result set, performance may be poor- data Iill be Iritten to disJ to avoid memory e#haustion, but the function itself Iill not return until the entire result set has been generated * future version of PL/pgSQL may alloI users to alloI users to define set6returning functions that do not have this limitation (urrently, the point at Ihich data begins being Iritten to disJ is controlled by the S.05D2!2 configuration variable *dministrators Iho have sufficient memory to store larger result sets in memory should consider increasing this parameter

2.2 Condicionales
)1 statements let you e#ecute commands based on certain conditions PL/pgSQL has four forms of )1-

)1 )1 )1 )1

5;!7 5;!7 5;!7 5;!7

!LS! !LS! )1 and !LS)1 5;!7

!LS!

%.2.1 '()*+E,
IF 9oolean-eCpression T<EN esta#entos END IF' Los estamentos )165;!7 son el formato m$s simple del )1 Los estamentos entre 5;!7 y !7/ )1 ser$n ejecutados si la condici"n se cumple !n caso contrario, ser$n ignorados IF F%user%i+ ./ 4 T<EN U!DATE users SET e#ail 2 F%e#ail ><ERE user%i+ 2 F%user%i+' END IF'

%.2.2 '()*+E,)ELSE
IF 9oolean-eCpression T<EN esta#entos ELSE esta#entos END IF'

Los estamentos )165;!76!LS! aadidos al )165;!7 le permiten especificar un juego alternativo de estamentos que deber+an ser ejecutados si la condici"n se eval:a a 1*LS! IF parenti+ IS NULL or parenti+ 2 '''' T<EN return &ullna#e' ELSE return Gp%true%&ilena#e(parenti+) AA ''H'' AA &ullna#e' END IF' IF F%count / 4 T<EN INSERT INTO users%count(count) ;ALUES(F%count)' RETURN ''t''' ELSE RETURN ''&''' END IF'

%.2.3 '()*+E,)ELSE '(


Los estamentos )1 pueden anidarse, tal como en el siguiente ejemploIF +e#o%ro=*seC 2 ''#'' T<EN prett$%seC 12 ''#an''' ELSE IF +e#o%ro=*seC 2 ''&'' T<EN prett$%seC 12 ''=o#an''' END IF' END IF' (uando use este formato, estar$ anidando un estamento )1 dentro de la parte !LS! de un estamento )1 superior 7ecesitar$ un estamenteo !7/ )1 por cada )1 anidado, y uno para el )16!LS! padre !sto funciona, pero es tedioso cuando e#isten muchas alternativas a ser chequeadas

%.2. '()*+E,)ELS'()ELSE
IF 9oolean-eCpression T<EN esta#entos - ELSIF 9oolean-eCpression T<EN esta#entos - ELSIF 9oolean-eCpression T<EN esta#entos ***00 - ELSE esta#entos 0 END IF' )165;!76!LS)16!LS! proporciona un m%todo m$s conveniente de chequear muchas alternativas en un estamento 1ormalmante es equivalente a comandos )165;!76!LS!6)165;!7 anidados, pero s"lo se necesita un !7/ )1 *qu+ tiene un ejemploIF nu#9er 2 4 T<EN result 12 ''Pero''' ELSIF nu#9er / 4 T<EN result 12 ''positiFe''' ELSIF nu#9er . 4 T<EN result 12 ''ne(atiFe''' ELSE -- G##7 tGe onl$ otGer possi9ilit$ is tGat nu#9er IS NULL result 12 ''NULL''' END IF' La secci"n !LS! final es opcional

2.3 3ucles Si!ples


(on los estamentos L..P, !4)5, B;)L! y 1.0, usted puede programar su funci"n PL/pgSQL para repetir una serie de comandos

%.3.1 L--P
-..eti)uetal//0 LOO! esta#entos END LOO!' L..P define un bucle incondicional que es repetido indefinidamente hasta que sea termiando por un estamento !4)5 o 0!5,07 La etiqueta opcional puede ser usada por estamentos !4)5 en bucles anidados para especificar qu% nivel de anidaci"n deber+a ser terminado

%.3.2 E.'*
EMIT - eti)ueta 0 - ><EN eCpresiDn 0' Si no se proporciona etiqueta, el bucle m$s al interior es terminado y el estamento m$s cercano a !7/ L..P es ejecutado a continuaci"n Si se proporciona etiqueta, esta debe ser la etiqueta del bucle o bloque m$s actual o de nivel e#terno !ntonces el bucle o bloque nombrado es terminado, y el control contin:a con el estamento que sigue al correspondiente !7/ del bucle/bloque Si B;!7 est$ presente, s"lo ocurrir$ la salida del bucle si la condici"n especificada es cierta, de lo contrario pasa al estamento tras !4)5 !jemplosLOO! -- al(unas co#putaciones IF count / 4 T<EN EMIT' -- eCit loop END IF' END LOO!' LOO! -- al(unas co#putaciones EMIT ><EN count / 4' END LOO!' EGIN -- al(unas co#putaciones IF stocOs / I44444 T<EN EMIT' -- ile(al* No pue+e usar EMIT &uera +e un LOO! END IF' END'

%.3.3 /+'LE
-..eti)ueta//0 ><ILE eCpresiDn LOO! esta#entos END LOO!' !l estamento B;)L! repite una secuencia de estamentos mientras que la condici"n se eval:e a verdadero La condici"n es chequeada jsuto antes de cada entrada al cuerpo del bucle Por ejemplo><ILE a#ount%o=e+ / 4 AND (i&t%certi&icate%9alance / 4 LOO! -- al(unas co#putaciones a)u5 END LOO!' ><ILE NOT 9oolean%eCpression LOO! -- al(unas co#putaciones a)u5 END LOO!'

%.3. (-R 0integer 1or)loop2


-..eti)ueta//0

FOR no#9re IN - RE;ERSE 0 eCpresiDn ** eCpresiDn LOO! esta#entos END LOO!' !ste formato de 1.0 crea un bucle que itera sobre un rango de valores enteros La variable nom%re es autom$ticamente definida como de tipo inte er y e#iste s"lo dentro del bucle Las dos e#presiones dando el menor y mayor valores del rango son evaluadas unavez se entra en el bucle !l intervalo de iteraci"n es de ? normalmente, pero es 6? cuando se especifica 0!=!0S! *lgunos ejemplosFOR i IN I**I4 LOO! -- al(unas eCpresiones a)u5 RAISE NOTICE ''i is 6''7i' END LOO!' FOR i IN RE;ERSE I4**I LOO! -- al(unas eCpresiones a)u5 END LOO!'

2.) 3ucles a tra4s de los &esultados de una 35s6ueda


,sando un tipo diferente de bucle 1.0, usted puede iterar a trav%s de los resultados de una consulta y manipular sus datos La sinta#is es-..eti)ueta//0 FOR re(istro A &ila IN select%)uer$ LOO! esta#entos END LOO!' * la variable re istro o fila le son sucesivamente asignadas todas las filas resultantes de la consulta S!L!(5 y el cuerpo del bucle es ejecutado para cada fila *qu+ tiene un ejemploCREATE FUNCTION cs%re&resG%#Fie=s () RETURNS INTEGER AS ' DECLARE #Fie=s RECORD' EGIN !ERFOR" cs%lo((''Re&resGin( #aterialiPe+ Fie=s***'')' FOR #Fie=s IN SELECT K FRO" cs%#aterialiPe+%Fie=s ORDER ? sort%Oe$ LOO!

-- AGora Q#Fie=sQ tiene un re(istro +e la Fista cs%#aterialiPe+%Fie=s !ERFOR" cs%lo((''Re&resGin( #aterialiPe+ Fie= '' AA )uote%i+ent(#Fie=s*#F%na#e) AA ''***'')' EMECUTE ''TRUNCATE TA LE '' AA )uote%i+ent(#Fie=s*#F%na#e)' EMECUTE ''INSERT INTO '' AA )uote%i+ent(#Fie=s*#F%na#e) AA '' '' AA #Fie=s*#F%)uer$' END LOO!' !ERFOR" cs%lo((''Done re&resGin( #aterialiPe+ Fie=s*'')' RETURN I' en+' ' LANGUAGE 'plp(s)l'' Sinel bucle es terminado por un estamento !4)5, el valor de la :ltima fila asignada es todav+a accesible tras la salida del bucle !l estamento 1.06)76!4!(,5! es otra forma de iterar sobre registros-..eti)ueta//0 FOR re(istro A &ila IN EMECUTE eCpresiDn%teCto LOO! esta#entos END LOO!' !sto es como el anterior formato, e#cepto porque el estamento origen S!L!(5 es especificado como una e#presi"n de te#to, la cual es evaluada y replanificada en cada entrada al bucle 1.0 !sto permite al programador seleccionar la velocidad de una consulta preplanificada o la fle#ibilidad de una consulta din$mica, tal como con un estamento plano !4!(,5!

NOTA- !l int%rprete PL/pgSQL actualmente ditingue los dos tipos de bucles1.0 &enteros o retornadores de registros' comprobando si la variable destino mencionada justo antes del 1.0 ha sido declarada como variable tipo registro/fila Si no es as+, se presume que es un bucle 1.0 con valor entero !sto puede causar algunos mensajes de error no intuitivos cuando el verdadero problema es, digamos, que uno se ha olvidado del nombre de la variable 1.0

3 &ursores
*dem$s de ejecutar una consulta completa al mismo tiempo, es posible configurar un cursor que encapsule la consulta, y luego leer del resultado de la consulta unas cuantas filas al tiempo ,na raz"n de hacer esto es para evitar sobrecargas de memoria cuando el resultado contiene un gran n:mero de filas &Sin embargo, los usuarios de PL/pgSQL no necesitar$n normalmente preocuparse por esto, ya que los bucles 1.0 autom$ticamente usan un cursor internamente para evitar problemas de memoria' ,n uso m$s interesante es retornar una referencia a un cursor que %l ha creado, permitiento al peticionario leer las filas !sto proporciona una forma eficiento de retornar largos juegos de filas desde funciones

7.1 Declarando 8aria*les Cursor


5odo el acceso a cursores en PL/pgSQL va a trav%s de variables cursor, las cuales son siempre del tipo de datos especial refcursor ,na forma de crear una variable tipo cursor es declararla como de tipo refcursor .tra forma es usar la sinta#is de declaraci"n de cursor, la cual en general esno#9re CURSOR - ( ar(u#entos ) 0 FOR select%)uer$ ' &7.5*- 1.0 puede ser reemplazado por )S para compatibilidad con .racle' Los argumentos, si los hay, son pares de tipos de datos name separados por comas que definen nombres a ser reemplazados por valores de par$metros en la consulta dada Los actuales valores a sustituir para estos nombres ser$n especificados m$s tarde, cuando el cursor es abierto *lgunos ejemplosDECLARE cursI re&cursor' cursE CURSOR FOR SELECT K &ro# tenOI' curs3 CURSOR (Oe$ int) IS SELECT K &ro# tenOI =Gere uni)ueI 2 Oe$' !stas tres variables tienen el tipo de datos refcursor, pero la primera puede ser usada con cualquier consulta, mientras que la segunda tiene una consulta completamente especificada para trabajar con ella, y la :ltima tiene una consulta parametrizada & 1ey ser$ reemplazado por un valor de par$metro entero cuando el cursor es abierto' La variable curs1 ser$ obviada, ya que no est$ asignada a ninguna consulta en particular

7.2 A*riendo Cursores


*ntes de que un cursor pueda ser utilizado para retornar filas, %ste debe ser abierto &esta es la acci"n equivalente al comando SQL /!(L*0! (,0S.0' PL/pgSQL tiene cuatro formas para el estamento .P!7, dos de las cuales usan variables cursor no asignadas y las otras dos usan variables cursor asignadas

3.2.1 -PE, (-R SELE&*


O!EN un9oun+-cursor FOR SELECT ***' La variable cursor es abierta y se le pasa la consulta especificada para ejecutar !l cursor no puede ser abierto a:n, y debe haber sido declarado como cursor no asignado &esto es, una simple variable refcursor' La consulta S!L!(5 es tratada de la misma forma que otros estamentos S!L!(5 en PL/pgSQLlos nombres de variables PL/pgSQL son sustituidos, y el plan de consulta es almacenado para su posible reutilizaci"n O!EN cursI FOR SELECT K FRO" &oo ><ERE Oe$ 2 #$Oe$'

3.2.2 -PE, (-R E.E&4*E

O!EN un9oun+-cursor FOR EMECUTE )uer$-strin(' La variable cursor es abierta y se le pasa la consulta especificada para ser ejecutada !l cursor no puede ser abierto a:n, y debe haber sido decalrado como cursor no asignado &esto es, una simpla variable refcursor' La consulta es especificada como una e#presi"n de te#to de la misma forma que en el comando !4!(,5! (omo es usual, esto le da fle#ibilidad para que la consulta pueda variar en cada ejecuci"n O!EN cursI FOR EMECUTE ''SELECT K FRO" '' AA )uote%i+ent(JI)'

3.2.3 -pening a bound cursor


O!EN 9oun+-cursor - ( ar(u#ent%Falues ) 0' !sta forma de .P!7 es usada para abrir una variable cursor cuya consulta le fu% asignada cuando %sta fue declarada !l cursor no puede ser abierto todav+a ,na lista de los actuales argumentos de los valores de las e#presiones debe aparecer si y s"lo si el cursor fue declarado para tomar argumentos !stos valores ser$n sustituidos en la consulta !l plan de consulta para un cursor asignado siempre es considerado como almacenable 6no hay equivalencia para !4!(,5! en %ste caso6 O!EN cursE' O!EN curs3(RE)'

7.3 9sando Cursores


,na vez un cursor ha sido abierto, %ste puede ser manipulado con los estamentos descritos aqu+ !stas manipulaciones no necesitan ocurrir en la misma funci"n que abri" el cursor Puede retornar un valor refcursor de una funci"n y permitir al peticionario operar con el cursor &internamente, un valor refcursor es simplemente la cadena nombre de una Portal conteniendo la consulta activa para el cursor !ste nombre puede ser pasado, asignado a otras variables refcursor, sin afectar al Portal' 5odos los Portales son impl+citamente cerrados al final de la transacci"n Por tanto un valor refcursor es :til para referenciar un cursor abierto s"lo hasta el final de la transacci"n

3.3.1 (E*&+
FETC< cursor INTO tar(et' 1!5(; retorna la siguiente fila desde el cursor a un destino, el cual puede ser una variable fila, registro o una lista de vairbales simples, separadas por comas, tal como en un S!L!(5 )75. *l igual que en un S!L!(5 )75., la variable especial 1.,7/ puede ser chequeada para ver si se obutvo o no una fila FETC< cursI INTO ro=Far' FETC< cursE INTO &oo79ar79aP'

3.3.2 &L-SE
CLOSE cursor' (L.S! cierra el Portal de un cursor abierto !sto puede ser suado para liberar recursos antes del final de una transacci"n, o para liberar la variable cursor para abrirla de nuevop CLOSE cursI'

3.3.3 Retornando &ursores


Las funciones PL/pgSQL pueden retornar cursores al peticionario !sto es usado para retornar m:ltiples filas o columnas desde la funci"n La funci"n abre el cursor y retorna el nombre del cursor al peticionario !l peticionario entonces puede obtener &con 1!5(;' filas desde el cursor !l cursor puede ser cerrado por el remitente, o ser$ cerrado autom$ticamente cuando termine la transacci"n

!l nombre del cursor retornado por la funci"n puede ser especificado por el peticionario o generado autom$ticamente !l siguiente ejemplo muestra c"mo un nombre de cursor puede ser proporcionado por el peticionarioCREATE TA LE test (col teCt)' INSERT INTO test ;ALUES ('IE3')' CREATE FUNCTION re&&unc(re&cursor) RETURNS re&cursor AS ' EGIN O!EN JI FOR SELECT col FRO" test' RETURN JI' END' ' LANGUAGE 'plp(s)l'' EGIN' SELECT re&&unc('&unccursor')' FETC< ALL IN &unccursor' CO""IT' !l siguiente ejemplo usa generaci"n autom$tica de nombre de cursorCREATE FUNCTION re&&uncE() RETURNS re&cursor AS ' DECLARE re& re&cursor' EGIN O!EN re& FOR SELECT col FRO" test' RETURN re&' END' ' LANGUAGE 'plp(s)l'' EGIN' SELECT re&&uncE()' re&&uncE -------------------.unna#e+ cursor I/ (I ro=) FETC< ALL IN Q.unna#e+ cursor I/Q' CO""IT'

5 Errores y Mensa6es
,se el estamento 0*)S! para retornar mensajes y lanzar errores RAISE leFel '&or#at' -7 Faria9le -***00' Los posibles niveles son /!8,9 &escribe el mensaje en el registro del servidor', L.9 &escribe el mensaje en el servidor con una prioridad alta', )71., 7.5)(! y B*07)79 &escribe el mensaje en el registro del servidor y lo env+a al cliente, con prioridad alta en ambos env+os', y !4(!P5).7 &lanza un error y aborta la actual transacci"n' Si los mensajes de error de una determinada prioridad son reportados al cliente, escritos en el registro del servidor, o ambos es es controlado por las variables de configuraci"n L.9D2)7D2!SS*9!S y (L)!75D2)7D2!SS*9!S =ea la 9u+a del *dminitrador de PostgreSQL para m$s informaci"n /entro del formato de la cadena, A es reemplazado por el siguiente argumento opcional de la representaci"n e#terna !scriba AA para emitir un literal A *dvierta que los argumentos opcionales deben ser variables simples, no e#presiones, y el formato debe ser un simple literal !jemplosRAISE NOTICE ''Callin( cs%create%Uo9(6)''7F%Uo9%i+' !n %ste ejemplo, el valor de v_jo%_id reemplazar$ el A en la cadena RAISE EMCE!TION ''IneCistent ID --/ 6''7user%i+' !sto abortar$ la transacci"n con el mensaje de error dado

:.1 ,xcepciones
PostgreSQL no tiene un modelo de manejo de e#cepciones demasiado elegante (uando el int%rprete, planificador/optimizador o ejecutor decide que el estamento no puede ser procesado, toda la transacci"n es abortada y el sistema salta al bucle principal para obtener la siguiente consultad desde la aplicaci"n cliente !s posible entrar en el mecanismo de error para averiguar qu% es lo que est$ pasando Pero actualmente es imposible decir qu% es lo que realmente caus" la cancelaci"n &error de conversi"n de entrada/salida, error de coma flotante, error de sinta#is' C es posible que el motor de base de datos est% en un estado inconsistente en %ste punto, as+ que podr+a retornar al ejecutor superior o la entrega de m$s comandos podr+a corromper toda la base de datos *s+, la :nica cosa que hace PL/pgSQL actualmente cuando se encuentra con una cancelaci"n durante la ejecuci"n de una funci"n o trigger es escribir adicionales mensajes de nivel 7.5)(!, indicando en qu% funci"n y cu$ndo &n:mero de l+nea y tipo de estamento' ocurri" !l error siempre para la ejecuci"n de la funci"n

7 Procedimientos *rigger
PL/pgSQL puede ser utilizado para definir triggers ,n procedimiento trigger es creado con el comando (0!*5! 1,7(5).7 como una funci"n sin argumentos y retornando un tipo tri er *dvierta que la funci"n debe ser declarada sin argumentos, aunque espere recibir argumentos espec+ficos en (0!*5! 50)99!0 6los argumentos trigger son pasados v+a 59D*09=, como veremos m$s adelante6 (uando una funci"n PL/pgSQL es denominada como tri er, varias variables especiales son creadas autom$ticamente en el bloque de nivel superior !stas son-

NEW 5ipo de datos 0!(.0/3 variable que almacena la nueva fila de base de datos para operaciones )7S!05/,P/*5! en triggers de nivel 0.B !sta variable es 7,LL en los triggers de nivel S5*5!2!75 OLD 5ipo de datos 0!(.0/3 variable que almacena la antigua fila de base de datos para operaciones ,P/*5!//!L!5! en triggers de nivel 0.B !sta variable es 7,LL en triggers de nivel S5*5!2!75 TG_NAME 5ipo de datos name3 variable que contiene el nombre del trigger actualmente disparado TG_W EN 5ipo de datos te,t3 una cadena de 8!1.0! o *15!0 dependiendo de la definici"n del trigger TG_LE!EL 5ipo de datos te,t3 una cadena de 0.B o S5*5!2!75 dependiendo de la definici"n del trigger TG_OP 5ipo de datos te,t3 una cadena de )7S!05, ,P/*5! o /!L!5! indicando por cu$l operaci"n se dispar" el trigger TG_"EL#D 5ipo de datos oid3 el )/ de objeto de la tabla que caus" la invocaci"n del trigger TG_"ELNAME 5ipo de datos name3 el nombre de la tabla que caus" la invocaci"n del trigger TG_NA"GS 5ipo de datos inte er3 el n:mero de argumentos proporcionado al procedimiento trigger en el estamento (0!*5! 50)99!0 TG_A"G!$% 5ipo de datos array de te,t3 los argumentos del estamento (0!*5! 50)99!0 !l +ndice cuenta desde K y puede ser dado como e#presi"n Lndices inv$lidos &M K or NO tgDnargs' resultan en un valor nulo ,na funci"n trigger debe retornar o 7,LL o un valor registro/fila teniendo e#actamente la misma estructura de la tabla que dispar" el trigger !l valor de retorno de un trigger de nivel 8!1.0! o *15!0 S5*5!2!75, o un trigger de nivel *15!0 0.B es ignorado3 tambi%n puede retornar 7,LL Sin embargo, cualquiera de estos tipos a:n pueden abortar toda la operaci"n del trigger lanzando un error

Los triggers de nivel 0.B lanzados antes &8!1.0!' pueden retornar 7,LL para sealar al gestor del trigger que se salte el resto de la operaci"n para esa fila &p ej , subsecuentes triggers no son lanzados, y el )7S!05/,P/*5!//!L!5! no ocurre para esa fila' Si un valor no 7,LL es retornado, entonces la operaci"n procede con ese valor de fila *dvierta que retornar un valor de fila diferente del valor original del nuevo &7!B' altera la fila que ser$ insertada o actualizada !s posible reemplazar valores simples directamente en 7!B y retornarlos, o construir un registro/fila completamente nuevo para retornarlo E-emplo "#.". /n E-emplo de Procedimiento Tri&&er en PL0p&S'L !ste trigger asegura que en cualquier momento en que una fila sea insertada o actualizada en la tabla, el actual nombre de usuario y fecha/hora son almacenadas en la fila C garantiza que un nombre de empleado es dado y que el salario es un valor positivo CREATE TA LE e#p ( no#9re%e#plea+o teCt7 salario inte(er7 ulti#a%&ecGa ti#esta#p7 ulti#o%usuario teCt )' CREATE FUNCTION e#p%sta#p () RETURNS TRIGGER AS ' EGIN -- Co#prue9a )ue se proporcionan no#9re%e#plea+o $ salario IF NE>*no#9re%e#plea+o ISNULL T<EN RAISE EMCE!TION ''El no#9re +el e#plea+o no pue+e ser un Falor NULO''' END IF' IF NE>*salario ISNULL T<EN RAISE EMCE!TION ''6 no pue+e tener un salario NULO''7 NE>*no#9re%e#plea+o' END IF' -- VWuiSn tra9aUa (ratisX IF NE>*salario . 4 T<EN RAISE EMCE!TION ''6 no pue+e tener un salario ne(atiFo''7 NE>*no#9re%e#plea+o' END IF' -- Recuer+a )uiSn $ cuYn+o GiPo el ca#9io NE>*ulti#a%&ecGa 12 ''no=''' NE>*ulti#o%usuario 12 current%user' RETURN NE>' END' ' LANGUAGE 'plp(s)l'' CREATE TRIGGER e#p%sta#p EFORE INSERT OR U!DATE ON e#p FOR EAC< RO> EMECUTE !ROCEDURE e#p%sta#p()'

18 E6emplos
*qu+ tiene unas cuantas funciones para demostrar lo sencillo que es escribir funciones PL/pgSQL Para ejemplos m$s complejos el programador podr+a echar un vistazo a los tests de regresi"n para PL/pgSQL ,n detalle importante en la escritura de funciones PL/pgSQL es el manejo de las comillas simples !l c"digo fuente de la funci"n en (0!*5! 1,7(5).7 debe ser un literal de cadena Las comillas simples dentro de literales cadena deben ser dobles o antecedidas por una barra invertida & %ac1slas(' 5odav+a seguimos buscando una alternativa elegante Por ahora, doblar las comillas simples como en los ejemplos es lo que deber+a usar (ualquier soluci"n para futuras versiones de PostgreSQL ser$ compatible Para una e#plicaci"n detallada y ejemplos sobre c"mo escapar comillas simples en diferentes situaciones, vea la Secci"n ?? ? ? E-emplo "#.1. /na simple funcin PL0p&S'L para incrementar un entero. !sta funci"n recibe un entero y lo incrementa en uno, retornando el valor incrementado CREATE FUNCTION a++%one (inte(er) RETURNS INTEGER AS ' EGIN RETURN JI Z I' END' ' LANGUAGE 'plp(s)l''

E-emplo "#.2. /na simple funcin PL0p&S'L para concatenar te3to. !sta funci"n recibe dos par$metros de te#to y retorna el resultado de su uni"n CREATE FUNCTION concat%teCt (TEMT7 TEMT) RETURNS TEMT AS ' EGIN RETURN JI AA JE' END' ' LANGUAGE 'plp(s)l'' E-emplo "#.). /na funcin PL0p&S'L para composicin de te3to. !n %ste ejemplo, tomamos !2P &una tabla' y un entero com argumentos de nuestra funci"n, la cual retorna un booleano Si el campo salary de la tabla !2P es 7,LL, nosotros retornamos f /e lo contrario comparamos dicho campo con el entero pasado a la funci"n y retornamos el resultado booleano de la comparaci"n &t o f' CREATE FUNCTION c%oFerpai+ (E"!7 INTEGER) RETURNS DECLARE e#prec ALIAS FOR JI' salli# ALIAS FOR JE' EGIN IF e#prec*salar$ ISNULL T<EN RETURN ''&''' END IF' RETURN e#prec*salar$ / salli#' END' ' LANGUAGE 'plp(s)l'' OOLEAN AS '

11 Portando desde -racle PL/SQL


Autor- 0oberto 2ello &Mrmello@fslc.usu.eduN' !sta secci"n e#plica las diferencias entre el PL/SQL de .racle y el PL/pgSQL de PostgreSQL con el objetivo de ayudar a los programadores a portar aplicaciones de .racle a PostgreSQL La mayor+a del c"digo e#puesto aqu+ es del m"dulo #rs2i ita 3lic1stream que yo &el autor' port% a PostgreSQL cuando desarroll% una tienda interna con .pen1orce )nc en el verano de @KKK
PL/pgSQL es similar a PL/SQL en muchos aspectos !s un lenguaje de bloques estructurados, imperativo &todas las variables tienen que ser declaradas' PL/SQL tiene muchas m$s caracter+sticas que su hom"nimo de PostgreSQL, pero PL/pgSQL permite una gran funcionalidad y es mejorado constantemente

11.1 Principales Di;erencias


*lgunas cosas que deber+a recordar cuando porte de .racle a PostgreSQL-

7o hay par$metros por defecto en PostgreSQL Puede volver a cargar funciones en PostgreSQL !sto es frecuentemente usado para saltarse la deficiencia de los par$metros por defecto Las asignaciones, bucles y condicionales son similares 7o es necesario para los cursores en PostgreSQL, s"lo ponga la consulta en el estamento 1.0 &vea ejemplo m$s adelante' !n PostgreSQL necesita escapar las comillas simples =ea la Secci"n ?? ? ?

11.1.1 Escapando &omillas Simples


!n PostgreSQL necesita escapar las comillas simples dentro de su definici"n de funci"n !sto es importante recordarlo para el caso de crear funciones que generan otras funciones, como en el !jemplo ?P6Q La 5abla ?P6? le ayudar$ &amar$ a esta pequea tabla'

Ta$la "#.". Es4uema de Escapado de 5omillas Simples.


No. &e 'om(lla s ? )so E*emplo "esulta&o

Para (0!*5! 1,7(5).7 foo&' tal cual iniciar/terminar 0!5,07S )75!9!0 *S cuerpos de H H L*79,*9! HplpgsqlH3 funci"n !n asignaciones, estamentos S!L!(5, para delimitar cadenas, etc (uando necesite dos comillas simples en su cadena de resultado sin terminar dicha cadena aDoutput -O HH8lahHH3 S!L!(5 < 10.2 users B;!0! fDnameOHHfoobarHH3 S!L!(5 < 10.2 users B;!0! fDnameOHfoobarH3

aDoutput -O aDoutput SS HH *7/ name L)T! HHHHfoobarHHHH *7/ HH

*7/ name L)T! HfoobarH *7/

(uando quiera aDoutput -O aDoutput SS comillas dobles HH *7/ name L)T! en su cadena HHHHfoobarHHHHHH de resultad y terminar dicha cadena (uando quiera dos comillas simples en la cadena de resultado &lo cual cuenta para U comillas' y terminar dicha cadena &@ m$s' Probablemente s"lo necesitar$ esto si usa una funci"n para generar otras funciones &como en el !jemplo ?P6Q'

*7/ name L)T! HfoobarH

?K

aDoutput -O aDoutput SS if vDM N liJe HHM NHH then HH if vDHH SS return HHM NHH3 end if3 referrerDJeys Jind SS HH liJe HHHHHHHHHH SS referrerDJeys JeyDstring SS HHHHHHHHHH then return HHHHHH SS referrerDJeys referrerDty pe SS HHHHHH3 end if3HH3

11.2 Portando "unciones


E-emplo "#.6. /na 7uncin Simple. *qu+ tiene una funci"n de .racleCREATE OR RE!LACE FUNCTION cs%&#t%9ro=ser%Fersion(F%na#e IN FarcGar7 F%Fersion IN FarcGar) RETURN FarcGar IS EGIN IF F%Fersion IS NULL T<EN RETURN F%na#e' END IF' RETURN F%na#e AA 'H' AA F%Fersion' END' H S<O> ERRORS'

=ayamos a trav%s de la funci"n para ver las diferencias con PL/pgSQL-

PostgreSQL ni tiene par$metros nominados ,sted tiene que especificarlos como *L)*S dentro de su funci"n .racle puede tener par$metros )7, .,5, y )7.,5 pasados a funciones !l )7.,5, por ejemplo, significa que el par$metro recibir$ un valor y retornar$ otro PostgreSQL s"lo tiene par$metros V)7V y las funciones s"lo pueden retornar un valor simple La palabra clave 0!5,07 en la funci"n prototype &no la funci"n %ody' retornar 0!5,07S en PostgreSQL Las funciones PostgreSQL son creadas usando comillas simples y delimitadores, as+ que tiene que escapar comillas simples dentro de sus funciones &lo cual puede ser engorroso en algunas ocasiones3 vea la Secci"n ?? ? ?' !l comando /s(o$ errors no e#iste en PostgreSQL

*s+ que veamos c"mo %sta funci"n quedar+a al portarla a PostgreSQLCREATE OR RE!LACE FUNCTION cs%&#t%9ro=ser%Fersion(;ARC<AR7 ;ARC<AR) RETURNS ;ARC<AR AS ' DECLARE F%na#e ALIAS FOR JI' F%Fersion ALIAS FOR JE' EGIN IF F%Fersion IS NULL T<EN return F%na#e' END IF' RETURN F%na#e AA ''H'' AA F%Fersion' END' ' LANGUAGE 'plp(s)l'' E-emplo "#.8. /na 7uncin 4ue crea otra 7uncin. !l siguiente procedimiento graba filas desde un estamento S!L!(5 y construye una gran funci"n con los resultados en estamentos )1, para una mayor eficiencia *dvierta particularmente las diferencias en cursores, bucles 1.0, y la necesidad de escapar comillas simples en PostgreSQL CREATE OR RE!LACE !ROCEDURE cs%up+ate%re&errer%t$pe%proc IS CURSOR re&errer%Oe$s IS SELECT K FRO" cs%re&errer%Oe$s ORDER ? tr$%or+er' a%output ;ARC<AR(R444)' EGIN a%output 12 'CREATE OR RE!LACE FUNCTION cs%&in+%re&errer%t$pe(F%Gost IN ;ARC<AR7 F%+o#ain IN ;ARC<AR7 F%url IN ;ARC<AR) RETURN ;ARC<AR IS EGIN'' FOR re&errer%Oe$ IN re&errer%Oe$s LOO! a%output 12 a%output AA ' IF F%' AA re&errer%Oe$*Oin+ AA ' LITE ''' AA re&errer%Oe$*Oe$%strin( AA ''' T<EN RETURN ''' AA re&errer%Oe$*re&errer%t$pe AA '''' END IF''' END LOO!' a%output 12 a%output AA ' RETURN NULL' END''' EMECUTE I""EDIATE a%output' END' H sGo= errors *qu+ tiene c"mo quedar+a la funci"n en PostgreSQLCREATE FUNCTION cs%up+ate%re&errer%t$pe%proc() RETURNS INTEGER AS ' DECLARE re&errer%Oe$s RECORD' -- Declare a (eneric recor+ to 9e use+ in a FOR a%output FarcGar(R444)' EGIN a%output 12 ''CREATE FUNCTION cs%&in+%re&errer%t$pe(;ARC<AR7;ARC<AR7;ARC<AR) RETURNS ;ARC<AR AS '''' DECLARE F%Gost ALIAS FOR JI' F%+o#ain ALIAS FOR JE'

F%url ALIAS FOR J3' EGIN ''' --- A+Fierta cD#o escanea#os a traFSs +e los resulta+os +e una consulta en un 9ucle FOR -- usan+o el constructor FOR .re(istro/* -FOR re&errer%Oe$s IN SELECT K FRO" cs%re&errer%Oe$s ORDER ? tr$%or+er LOO! a%output 12 a%output AA '' IF F%'' AA re&errer%Oe$s*Oin+ AA '' LITE '''''''''' AA re&errer%Oe$s*Oe$%strin( AA '''''''''' T<EN RETURN '''''' AA re&errer%Oe$s*re&errer%t$pe AA ''''''' END IF'''' END LOO!' a%output 12 a%output AA '' RETURN NULL' END' '''' LANGUAGE ''''plp(s)l'''''''' -- Esto &unciona por)ue no esta#os sustitu$en+o Faria9les* -- De lo contrario &allar5a* "ire !ERFOR" para otra &or#a +e eUecutar &unciones* EMECUTE a%output' END' ' LANGUAGE 'plp(s)l'' E-emplo "#.(. /n Procedimiento con un montn de manipulacin de cadenas y par9metros O/T. !l siguiente procedimiento de .racle PL/SQL es usado para interpretar una ,0L y retornar varios elementos &m$quina, ruta y consulta' !s un procedimiento porque en las funciones PL/pgSQL s"lo puede ser retornado un valor &vea la Secci"n ?? F' !n PostgreSQL, una forma de salvar esto es dividir el procedimiento en tres funciones diferentes- una para retornar el nombre de m$quina, otra para la ruta y otra para la consulta CREATE OR RE!LACE !ROCEDURE cs%parse%url( F%url IN ;ARC<AR7 F%Gost OUT ;ARC<AR7 -- TGis =ill 9e passe+ 9acO F%patG OUT ;ARC<AR7 -- TGis one too F%)uer$ OUT ;ARC<AR) -- An+ tGis one is a%posI INTEGER' a%posE INTEGER' 9e(in F%Gost 12 NULL' F%patG 12 NULL' F%)uer$ 12 NULL' a%posI 12 instr(F%url7 'HH')' -- !ost(reSWL not tiene una &unciDn instr IF a%posI 2 4 T<EN RETURN' END IF' a%posE 12 instr(F%url7 'H'7 a%posI Z E)' IF a%posE 2 4 T<EN F%Gost 12 su9str(F%url7 a%posI Z E)' F%patG 12 'H'' RETURN' END IF' F%Gost 12 su9str(F%url7 a%posI Z E7 a%posE - a%posI - E)' a%posI 12 instr(F%url7 'X'7 a%posE Z I)' IF a%posI 2 4 T<EN F%patG 12 su9str(F%url7 a%posE)' RETURN' END IF' F%patG 12 su9str(F%url7 a%posE7 a%posI - a%posE)' F%)uer$ 12 su9str(F%url7 a%posI Z I)' END' H sGo= errors' *qu+ tiene c"mo %ste procedimiento podr+a ser trasladado a PostgreSQLCREATE OR RE!LACE FUNCTION cs%parse%url%Gost(;ARC<AR) RETURNS ;ARC<AR AS '

DECLARE F%url ALIAS FOR JI' F%Gost ;ARC<AR' F%patG ;ARC<AR' a%posI INTEGER' a%posE INTEGER' a%pos3 INTEGER' EGIN F%Gost 12 NULL' a%posI 12 instr(F%url7''HH'')' IF a%posI 2 4 T<EN RETURN ''''' -- Return a 9lanO END IF' a%posE 12 instr(F%url7''H''7a%posI Z E)' IF a%posE 2 4 T<EN F%Gost 12 su9str(F%url7 a%posI Z E)' F%patG 12 ''H''' RETURN F%Gost' END IF' F%Gost 12 su9str(F%url7 a%posI Z E7 a%posE - a%posI - E )' RETURN F%Gost' END' ' LANGUAGE 'plp(s)l''

NOTA- PostgreSQL no tiene una funci"n instr, as+ que tendr$ que solventarlo usando una combinaci"n de otras funciones Co me cre% mis propias funciones instr que hacen e#actamente lo mismo que las de .racle =ea la Secci"n ?? Q para el c"digo

11.3 Procedi!ientos
Los procedimientos de .racle le dan al programador m$s fle#ibilidad porque nada necesita ser e#pl+citamente retornado, pero esto mismo se puede hacer a trav%s de los par$metros )7.,5 o .,5 ,n ejemploCREATE OR RE!LACE !ROCEDURE cs%create%Uo9(F%Uo9%i+ IN INTEGER) IS a%runnin(%Uo9%count INTEGER' !RAG"A AUTONO"OUS%TRANSACTION'(I) EGIN LOCT TA LE cs%Uo9s IN EMCLUSI;E "ODE'(E) SELECT count(K) INTO a%runnin(%Uo9%count FRO" cs%Uo9s ><ERE en+%sta#p IS NULL' IF a%runnin(%Uo9%count / 4 T<EN CO""IT' -- &ree locO(3) raise%application%error(-E44447 'Una9le to create a ne= Uo91 a Uo9 is currentl$ runnin(*')' END IF' DELETE FRO" cs%actiFe%Uo9' INSERT INTO cs%actiFe%Uo9(Uo9%i+) ;ALUES (F%Uo9%i+)' EGIN INSERT INTO cs%Uo9s (Uo9%i+7 start%sta#p) ;ALUES (F%Uo9%i+7 s$s+ate)' EMCE!TION ><EN +up%Fal%on%in+eC T<EN NULL' -- +on't =orr$ i& it alrea+$ eCists(R) END' CO""IT' END' H sGo= errors Los procedimientos como %ste pueden ser f$cilmente convertidos a funciones PostgreSQL retornando un )75!9!0 !ste procedimiento en particular es interesante porque nos puede ensear algunas cosas-

+,7o hay ning:n estamento pragm$tico en PostgreSQL +.-

Si usted realiza un L.(T 5*8L! en PL/pgSQL, el bloqueo &locJ' no ser$ liberado hasta que la transacci"n no termine +/5ampoco puede tener transacciones en procedimientos PL/pgSQL 5oda la funci"n &y otras funciones llamadas desde %sta' es ejecutada en una transacci"n, y PostgreSQL retira los resultados si algo va mal Por lo tanto s"lo est$ permitido un estamento 8!9)7 +0La e#cepci"n a esto es cuando tuviera que ser reemplazado por un estamento )1 *s+ que veamos una de las formas de portar %ste procedimiento a PL/pgSQLCREATE OR RE!LACE FUNCTION cs%create%Uo9(INTEGER) RETURNS INTEGER AS ' DECLARE F%Uo9%i+ ALIAS FOR JI' a%runnin(%Uo9%count INTEGER' a%nu# INTEGER' -- !RAG"A AUTONO"OUS%TRANSACTION' EGIN LOCT TA LE cs%Uo9s IN EMCLUSI;E "ODE' SELECT count(K) INTO a%runnin(%Uo9%count FRO" cs%Uo9s ><ERE en+%sta#p IS NULL' IF a%runnin(%Uo9%count / 4 T<EN -- CO""IT' -- &ree locO RAISE EMCE!TION ''Una9le to create a ne= Uo91 a Uo9 is currentl$ runnin(*''' END IF' DELETE FRO" cs%actiFe%Uo9' INSERT INTO cs%actiFe%Uo9(Uo9%i+) ;ALUES (F%Uo9%i+)' SELECT count(K) into a%nu# FRO" cs%Uo9s ><ERE Uo9%i+2F%Uo9%i+' IF NOT FOUND T<EN -- I& notGin( =as returne+ in tGe last )uer$ -- TGis Uo9 is not in tGe ta9le so lets insert it* INSERT INTO cs%Uo9s(Uo9%i+7 start%sta#p) ;ALUES (F%Uo9%i+7 s$s+ate())' RETURN I' ELSE RAISE NOTICE ''[o9 alrea+$ runnin(*'''(I) END IF' RETURN 4' END' ' LANGUAGE 'plp(s)l''

+,-

*dvierta que puede enviar noticias &o errores' in PL/pgSQL

11.) Pa6uetes
NOTA- 7o he hecho mucho con los paquetes, as+ que si detecta errores h$gamelo saber Los paquetes son una forma que .racle le proporciona para encapsular estamentos y funciones PL/SQL en una entidad, tal como las clases de Wava, donde usted define m%todos y objetos ,sted puede acceder a estos objetos/m%todos con un punto V V &dot' *qu+ tiene un ejemplo de paquete .racle de *(S R &el #rs2i ital 3ommunity System'CREATE OR RE!LACE !ACTAGE OD? acs AS FUNCTION a++%user ( user%i+ IN users*user%i+6T?!E DEFAULT NULL7 o9Uect%t$pe IN acs%o9Uects*o9Uect%t$pe6T?!E DEFAULT 'user'7 creation%+ate IN acs%o9Uects*creation%+ate6T?!E DEFAULT s$s+ate7 creation%user IN acs%o9Uects*creation%user6T?!E DEFAULT NULL7 creation%ip IN acs%o9Uects*creation%ip6T?!E DEFAULT NULL7 *** ) RETURN users*user%i+6T?!E IS F%user%i+ users*user%i+6T?!E' F%rel%i+ #e#9ersGip%rels*rel%i+6T?!E' EGIN

F%user%i+ 12 acs%user*ne= (user%i+7 o9Uect%t$pe7 creation%+ate7 creation%user7 creation%ip7 e#ail7 *** RETURN F%user%i+' END' END acs' H sGo= errors 7osotros portaremos esto a PostgreSQL creando los diferentes objetos del paquete .racle como funciones con una convenci"n de nombres standard 5enemos que poner atenci"n en algunos detalles, tales como la falta de par$metros por defecto en las funciones PostgreSQL !l paquete anterior ser+a algo como estoCREATE FUNCTION acs%%a++%user(INTEGER7INTEGER7;ARC<AR7TI"ESTA"!7INTEGER7INTEGER7***) RETURNS INTEGER AS ' DECLARE user%i+ ALIAS FOR JI' o9Uect%t$pe ALIAS FOR JE' creation%+ate ALIAS FOR J3' creation%user ALIAS FOR JR' creation%ip ALIAS FOR J8' *** F%user%i+ users*user%i+6T?!E' F%rel%i+ #e#9ersGip%rels*rel%i+6T?!E' EGIN F%user%i+ 12 acs%user%%ne=(user%i+7o9Uect%t$pe7creation%+ate7creation%user7creation%ip7 ***)' *** RETURN F%user%i+' END' ' LANGUAGE 'plp(s)l''

11.".1 E.E&4*E
La versi"n PostgreSQL de !4!(,5! funciona de maravilla, pero tiene que recordar usar literales entrecomillados &5!45' y cadenas entrecomilldas &5!45' tal como se describe en la Secci"n X R Los constructores del tipo /0/34./ **S/L/3. 5 from '1**6 no funcionar$n a menos que use estas funciones

11.".2 -ptimi9ando las (unciones PL/pgSQL


PostgreSQL le da dos modificadores de creaci"n de funciones para optimizar la ejecuci"n- iscac(a%le &esta funci"n siempre retorna el mismo resultado cuando se le dan los mismos argumentos' y isstrict &la funci"n retorna 7,LL si cualquiera de los argumentos es 7,LL' (onsulte la referencia de (0!*5! 1,7(5).7 para m$s detalles Para hacer uso de estos atributos de optimizaci"n, usted tiene que usar el modificador B)5; en su estamento (0!*5! 1,7(5).7 *lgo comoCREATE FUNCTION &oo(***) RETURNS INTEGER AS ' *** ' LANGUAGE 'plp(s)l' >IT< (isstrict7 iscacGa9le)'

11.%.1 &:digo para mis 1unciones instr


!sta funci"n podr+a probablemente ser integrada --- &unciDn instr )ue i#ita a la +e Oracle -- SintaCis1 instr(strin(I7strin(E7-n07-#0) +on+e -0 +enota parY#etros opcionales* --- usca strin(I e#pePan+o por el carYcter n para la ocurrencia # -- +e strin(E* Si n es ne(atiFa7 9usca Gacia atrYs* Si # no es proporciona+a7 -- asu#e I (la 9\s)ue+a se inicia en el pri#er carYcter)* --- por Ro9erto "ello (r#ello]&slc*usu*e+u) -- #o+i&ica+a por Ro9ert GasPe=sOi ((rasPe=]polan+*co#) -- Licencia+a 9aUo la G!L FE o si(uientes* --

CREATE FUNCTION instr(;ARC<AR7;ARC<AR) RETURNS INTEGER AS ' DECLARE pos inte(er' EGIN pos12 instr(JI7JE7I)' RETURN pos' END' ' LANGUAGE 'plp(s)l'' CREATE FUNCTION instr(;ARC<AR7;ARC<AR7INTEGER) RETURNS INTEGER AS ' DECLARE strin( ALIAS FOR JI' strin(%to%searcG ALIAS FOR JE' 9e(%in+eC ALIAS FOR J3' pos inte(er NOT NULL DEFAULT 4' te#p%str ;ARC<AR' 9e( INTEGER' len(tG INTEGER' ss%len(tG INTEGER' EGIN IF 9e(%in+eC / 4 T<EN te#p%str 12 su9strin((strin( FRO" 9e(%in+eC)' pos 12 position(strin(%to%searcG IN te#p%str)' IF pos 2 4 T<EN RETURN 4' ELSE RETURN pos Z 9e(%in+eC - I' END IF' ELSE ss%len(tG 12 cGar%len(tG(strin(%to%searcG)' len(tG 12 cGar%len(tG(strin()' 9e( 12 len(tG Z 9e(%in+eC - ss%len(tG Z E' ><ILE 9e( / 4 LOO! te#p%str 12 su9strin((strin( FRO" 9e( FOR ss%len(tG)' pos 12 position(strin(%to%searcG IN te#p%str)' IF pos / 4 T<EN RETURN 9e(' END IF' 9e( 12 9e( - I' END LOO!' RETURN 4' END IF' END' ' LANGUAGE 'plp(s)l'' --- #o+i&ica+a por Ro9ert GasPe=sOi ((rasPe=]polan+*co#) -- Licencia+a 9aUo la G!L FE o si(uientes* -CREATE FUNCTION instr(;ARC<AR7;ARC<AR7INTEGER7INTEGER) RETURNS INTEGER AS ' DECLARE strin( ALIAS FOR JI' strin(%to%searcG ALIAS FOR JE' 9e(%in+eC ALIAS FOR J3' occur%in+eC ALIAS FOR JR' pos inte(er NOT NULL DEFAULT 4' occur%nu#9er INTEGER NOT NULL DEFAULT 4' te#p%str ;ARC<AR' 9e( INTEGER' i INTEGER' len(tG INTEGER' ss%len(tG INTEGER' EGIN IF 9e(%in+eC / 4 T<EN 9e( 12 9e(%in+eC' te#p%str 12 su9strin((strin( FRO" 9e(%in+eC)' FOR i IN I**occur%in+eC LOO! pos 12 position(strin(%to%searcG IN te#p%str)'

IF i 2 I T<EN 9e( 12 9e( Z pos - I' ELSE 9e( 12 9e( Z pos' END IF' te#p%str 12 su9strin((strin( FRO" 9e( Z I)' END LOO!' IF pos 2 4 T<EN RETURN 4' ELSE RETURN 9e(' END IF' ELSE ss%len(tG 12 cGar%len(tG(strin(%to%searcG)' len(tG 12 cGar%len(tG(strin()' 9e( 12 len(tG Z 9e(%in+eC - ss%len(tG Z E' ><ILE 9e( / 4 LOO! te#p%str 12 su9strin((strin( FRO" 9e( FOR ss%len(tG)' pos 12 position(strin(%to%searcG IN te#p%str)' IF pos / 4 T<EN occur%nu#9er 12 occur%nu#9er Z I' IF occur%nu#9er 2 occur%in+eC T<EN RETURN 9e(' END IF' END IF' 9e( 12 9e( - I' END LOO!' RETURN 4' END IF' END' ' LANGUAGE 'plp(s)l''

http://www.sobl.org/traducciones/postgresql-develdoc/plpgsql.html

También podría gustarte