Documentos de Académico
Documentos de Profesional
Documentos de Cultura
PostgreSQL permite extender las funciones predefinidas en PL/pgsql usando un mecanismo para
crear funciones en su lenguaje nativo de programación como es C .
Esto permite ampliar nuestro abanico de posibilidades al desarrollar nuestra propias funciones
para que ejecuten tareas específicas o que sean críticas para el motor de base de datos, donde la
opciones de PL/pgsql o PL/python u otro lenguaje procedural que no nos satisface por completo.
Lo primero que debemos tener en cuenta es que no debemos confundir un lenguaje procedural PL
con funciones UDF, un lenguaje procedural implementa mecanismos propios para soportar ese
lenguaje por ejemplo PL/python que evidentemente también están escritos en C.
Implementar un lenguaje procedural es uno de los aspectos más avanzados que tiene PostgreSQL
y para la finalidad de este artículo no lo vamos a tomar en cuenta.
2.- Instalar el compilador de C y “C++” entre otras herramientas como el editor Nano y
las net-tools
P ágin a |1
Crear funciones en C para PostgreSQL
Hasta aquí ya PostgreSQL está instalado en ámbito local (localhost) y ejecutándose en espera de
comandos por parte del usuario, lo podemos comprobar mostrando los procesos de la cuenta
postgres
ps –u postgres u
P ágin a |2
Crear funciones en C para PostgreSQL
Por defecto la cuenta de gestión de la base de datos se llama postgres, pero es costumbre crear
una propia con suficiente privilegios para desenvolvernos en él, la configuración estándar no
permite mostrar la base de datos fuera de tu ámbito local (localhost) cambiaremos este
comportamiento más adelante para que podamos usar pgAdmin sin problemas
sudo su – postgres
createuser –s –d –P sqlman
P ágin a |3
Crear funciones en C para PostgreSQL
También debemos hacer cambios en dos archivos de configuración para que pgAdmin pueda
conectarse a PostgreSQL estos archivos son postgresql.conf y pg_hba.conf ambos están en la
carpeta /etc/postgresql/12/main. Se usa un editor de texto como nano para realizar dichos
cambios con las siguientes llamadas:
Original
#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------
# - Connection Settings –
Modificado
#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------
# - Connection Settings -
P ágin a |4
Crear funciones en C para PostgreSQL
Antes que nada debemos conocer cuál es nuestra dirección IP para poder crear la entrada
correspondiente dentro del archivo, usaremos el siguiente comando:
ifconfig
La dirección IP que buscamos está en la primera interface activa enp0s3 allí está la inet que en mi
máquina de pruebas es 192.168.2.59, es posible que en tu caso aparezca eth0 o lan0 u otra
diferente
Ya con este valor vamos a nuestro archivo pg_hba.conf y agregamos la siguiente línea que esta
remarcada en negrillas en IPV4 local connections
# DO NOT DISABLE!
# If you change this first entry you will need to make sure that the
# database superuser can access the database using some other method.
# Noninteractive access to all databases is required during automatic
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local all postgres peer
P ágin a |5
Crear funciones en C para PostgreSQL
Desde pgAdmin agregaremos nuestro servidor localhost, lo primero que pide la primera vez es
especificar una contraseña maestra la cual quedara registrada y que se usara cada vez que le lance
el pgAdmin nuevamente.
En la ficha General
En la ficha Connection
P ágin a |6
Crear funciones en C para PostgreSQL
Trabajaremos con las siguientes versiones de las herramientas gcc 7.5.0, g++ 7.5.0, ld 2.30 y make
4.1. Ejecute para cada programa en su terminal de la siguiente forma:
gcc –-version
g++ --version
ld –-version
make –version
Si por alguna razón no coinciden alguna de las versiones se debe proceder a reinstalar las build-
essential con apt.
Desde el punto de vista de un programador se puede escribir código C usando un simple editor de
texto como vim o nano y ejecutar la compilación usando la terminal con apoyo de make.
Si no es de tu gusto también puedes usar editores alternos como sublime-text o vscode, pero si
quieres más potencia entonces te recomiendo Code::Blocks, para instalar Code::Blocks ejecuta lo
siguiente:
P ágin a |7
Crear funciones en C para PostgreSQL
En youtube existen muchos tutoriales sobre cómo usar este IDE para sacarle el mayor provecho
posible
P ágin a |8
Crear funciones en C para PostgreSQL
Desde SQL se crean las sentencias necesarias para crear las funciones según su tipo, en este caso
nos enfocamos en las funciones de C, la sentencia seria de la siguiente manera:
En este caso $libdir es reemplazado por PostgreSQL por la ruta por defecto que le fue indicada
cuando se hizo la compilación.
La función suma_uno será referenciada por PostgreSQL, donde será ejecutado en el momento
que se precise.
Todas las funciones son compiladas en objetos de carga dinámica (también llamadas bibliotecas
compartidas que tienen extensiones .so) y son cargadas por el servidor PostgreSQL bajo demanda.
P ágin a |9
Crear funciones en C para PostgreSQL
1. Por posición: los parámetros se introducen en el mismo orden como fueron declarados
2. Dinámicos: la función soporta un número indeterminado de parámetros
3. Por posición notacional: los argumentos se pasan asociados a los nombres de los
parámetros
4. Por defecto: parámetros con valores por DEFAULT
El uso de la palabra reservada STRICT significa que cualquier parámetro pasado a la función con
valor NULL el resultado a devolver por la función también será NULL, más adelante veremos cómo
controlar los parámetros pasados como NULL dentro de nuestras funciones.
En este caso el parámetro tiene un valor por defecto de 500 y será pasado a nuestra función. No
es lo mismo llamar a la función suma_uno() que suma_uno(NULL), la primera toma el valor por
DEFAULT y la segunda se está pasando un valor NULL explícitamente por lo cual la función
devolverá NULL.
Las funciones en PostgeSQL pueden ser declaradas para aceptar un número de argumentos
variables que deberán ser del mismo tipo, estos argumentos serán pasados a la función como un
P á g i n a | 10
Crear funciones en C para PostgreSQL
array. Este parámetro tiene que ser declarado como el último dentro de la posición con VARIADIC
y a su vez declararlo como tipo array según su tipo. Por ejemplo:
La posición notacional asocia el nombre del parámetro con el valor del argumento y es pasada a la
función. Su utilidad radica en que permite pasar fácilmente muchos parámetros sin importar el
orden. Por ejemplo:
SELECT suma_todo(
b => 10,
c => 5,
a => 1
);
P á g i n a | 11
Crear funciones en C para PostgreSQL
La sobrecarga de funciones
En PostgreSQL una función se dice que esta sobrecargada cuando la misma función puede pasarle
uno o más argumentos de tipo diferentes o puede retornar un valor con un tipo diferente, el
concepto pareciera ser bastante simple, pero hay que prestarle atención. Veamos la siguiente
declaración de las siguientes funciones:
Como muestra el ejemplo la función suma_uno tiene dos variantes: la primera pasa el parámetro
tipo integer mientras que la segunda pasa el parámetro tipo double precision, ambas devuelven el
tipo correspondiente la primera tipo integer y la segunda tipo double precision. Si observa bien
se llama a la función correspondiente en su biblioteca; suma_uno pasa un integer como
argumento porque así está declarada en biblioteca mientras que suma_uno_float8 recibe un
argumento de tipo float8 en C que equivale decir double precision desde PostgreSQL. Si
ejecutamos:
SELECT suma_uno(10);
SELECT suma_uno(10.5);
Ya preparado nuestro entorno deb trabajo y visto la teoría de las llamadas a las funciones,
pasaremos a crear una función sencilla el famoso “Hola Mundo!!!”
P á g i n a | 12
Crear funciones en C para PostgreSQL
Las funciones en C para PostgreSQL siguen unas convenciones muy particulares que se deben
respetar siempre.
Los tipos por valor pueden ser solamente de una longitud de 1, 2 o 4 bytes. Debes ser cuidadoso al
definir tus tipos de datos porque deben tener el mismo tamaño en todas las arquitecturas. Por
ejemplo el tipo long es peligroso porque tiene 4 bytes en algunas máquinas y 8 bytes en otras,
mientras que el tipo int son 4 bytes en la mayoría de las máquinas Unix.
La convención de tipo de C indica el tamaño para los tipos de datos donde un intxx indica xx bits,
en cambio en SQL un tipo de datos intx indica x bytes, por ejemplo el tipo smallint de SQL tiene un
tamaño de 2 bytes (int2) que en C equivale a int16 o sea 16 bits.
En la siguiente tabla se muestran las equivalencias entre los tipos de SQL y tipos de C
P á g i n a | 13
Crear funciones en C para PostgreSQL
Ahora que sabes cómo definir los tipos de datos entre SQL y C, es tiempo de conocer como ubicar
los archivos que contiene las definiciones de esos tipos, los famosos archivos de cabecera.
pg_config --help
Empleo:
pg_config [OPCIÓN]...
Opciones:
--bindir muestra la ubicación de ejecutables de usuario
--docdir muestra la ubicación de archivos de documentación
--htmldir muestra la ubicación de archivos de documentación HTML
--includedir muestra la ubicación de archivos de encabezados C
de las interfaces cliente
--pkgincludedir muestra la ubicación de otros archivos de
encabezados C
--includedir-server muestra la ubicación de archivos de encabezados C
del servidor
--libdir muestra la ubicación de bibliotecas
de código objeto
--pkglibdir muestra la ubicación de módulos para carga dinámica
--localedir muestra la ubicación de archivos de soporte de
configuraciones locales
--mandir muestra la ubicación de páginas de manual
--sharedir muestra la ubicación de archivos de soporte
P á g i n a | 14
Crear funciones en C para PostgreSQL
independientes de arquitectura
--sysconfdir muestra la ubicación de archivos de configuración
global del sistema
--pgxs muestra la ubicación del archivo makefile
para extensiones
--configure muestra las opciones que se dieron a «configure»
cuando PostgreSQL fue construido
--cc muestra el valor de CC cuando PostgreSQL fue construido
--cppflags muestra el valor de CPPFLAGS cuando PostgreSQL fue
construido
--cflags muestra el valor de CFLAGS cuando PostgreSQL fue
construido
--cflags_sl muestra el valor de CFLAGS_SL cuando PostgreSQL fue
construido
--ldflags muestra el valor de LDFLAGS cuando PostgreSQL fue
construido
--ldflags_ex muestra el valor de LDFLAGS_EX cuando PostgreSQL fue
construido
--ldflags_sl muestra el valor de LDFLAGS_SL cuando PostgreSQL fue
construido
--libs muestra el valor de LIBS cuando PostgreSQL fue
construido
--version muestra la versión de PostgreSQL
-?, --help muestra esta ayuda, luego sale
Para poder desarrollar nuestra funciones debemos conocer donde se encuentra los archivos
cabecera que necesita el compilador de C ejecutando
pg_config –-includedir-server
/usr/include/postgresql/12/server
pg_config –-pkgincludedir
/usr/incldue/postgresql
pg_config –-libdir
/usr/lib/x86_64-linux-gnu
pg_config –-pkglibdir
/usr/lib/postgresql/12/lib
ls `pg_config –-includedir-server`
P á g i n a | 15
Crear funciones en C para PostgreSQL
ls `pg_config -–pkgincludedir`
ls `pg_config –-libdir`
Ls `pg_config –-pkglibdir`
El resultado de la ejecución debe mostrar los archivos correspondientes de cada carpeta, sabiendo
esto aprenderás a continuación como estructurar una función en C diseñada para PostgreSQL.
Listado saludar.c
Las líneas 1 y 2 se deben declarar los archivos de cabecera postgres.h y fmgr.h en ese orden.
El archivo postgres.h contiene las definiciones de los tipos base entre otras cosas, el archivo
fmgr.h contiene la macros que gestionan las funciones y hace la interface de llamadas a las
mismas.
P á g i n a | 16
Crear funciones en C para PostgreSQL
En caso de que por error lo definas en otro archivo el compilador devolverá el siguiente error:
En la línea 8 PG_FUNCTION_INFO_V1 es una macro construye una estructura que estará asociada
al nombre de la función dada, se le pasa como argumento el nombre de la función a declarar, esto
es obligatorio y debe estar declarado para cada función que vayamos a crear.
El Datum, en la línea 10, contiene un valor cualquiera de un tipo pasado por valor o un puntero a
un tipo pasado por referencia de la función declarada
Al definir la función saludar en la línea 11, se recibe como argumento PG_FUNCTION_ARGS, esta
macro se encarga de gestionar todos los argumentos pasados a la función incluyendo los
argumentos con valor NULL o cuando no se pasa argumento alguno a la función.
La línea 13 declara un puntero text donde se asignara el valor del argumento que es devuelto por
la macro PG_GETARG_TEXT_PP, observe que a la macro se le pasa el índice de la posición del
argumento que comienza en cero (0).
Cada macro de la forma PG_GET_ARG…(n) devuelve el valor en la posición del argumento para el
tipo que fue declarado.
P á g i n a | 17
Crear funciones en C para PostgreSQL
Para compilar el código saludar debemos invocar al compilador gcc con una serie de opciones
específica para el modelo de compilación.
$ mkdir pgtest
3.- Dentro de la carpeta pgtest crear dos carpetas una se llamara source y la otra lib.
$ cd pgtest
$ mkdir source
$ mkdir lib
$ cd pgtest
$ nano saludar.c
P á g i n a | 18
Crear funciones en C para PostgreSQL
#include "postgres.h"
#include "fmgr.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(saludar);
Datum
saludar(PG_FUNCTION_ARGS)
{
text *t = PG_GETARG_TEXT_PP(0);
PG_RETURN_TEXT_P(t);
}
P á g i n a | 19