Bien, encontré una respuesta. En PostgreSQL, puede escribir funciones usando Python. Para habilitar el uso de Python, debe instalar la versión específica de Python que necesita su instalación de PostgreSQL y tenerla disponible en la variable de entorno PATH. Puede averiguar qué versión de Python necesita su instalación de PostgreSQL consultando las notas de instalación. Actualmente estoy usando PostgreSQL 9.6.5 en Windows y requiere Python 3.3. Inicialmente probé la última versión de Python 3.6, pero no funcionó. Me conformé con el último Python 3.3 para Windows, que es 3.3.5.
Después de instalar Python, lo habilita en PostgreSQL ejecutando CREATE EXTENSION plpython3u;
en su base de datos como se documenta aquí https://www.postgresql.org/docs /actual/estática/plpython.html
. A partir de ahí, puede escribir cualquier función con cuerpos de Python.
Para mi caso específico para convertir de bytea
a double precision[]
y viceversa, escribí las siguientes funciones:
CREATE FUNCTION bytea_to_double_array(b bytea)
RETURNS double precision[]
LANGUAGE 'plpython3u'
AS $BODY$
if 'struct' in GD:
struct = GD['struct']
else:
import struct
GD['struct'] = struct
return struct.unpack('<' + str(int(len(b) / 8)) + 'd', b)
$BODY$;
CREATE FUNCTION double_array_to_bytea(dblarray double precision[])
RETURNS bytea
LANGUAGE 'plpython3u'
AS $BODY$
if 'struct' in GD:
struct = GD['struct']
else:
import struct
GD['struct'] = struct
# dblarray here is really a list.
# PostgreSQL passes SQL arrays as Python lists
return struct.pack('<' + str(int(len(dblarray))) + 'd', *dblarray)
$BODY$;
En mi caso, todos los dobles se almacenan en little endian, por lo que uso <
. También guardo en caché la importación de la struct
módulo en el diccionario global como se describe en https://stackoverflow.com/a/15025425/5274457 . Usé GD en lugar de SD porque quiero que la importación esté disponible en otras funciones que pueda escribir. Para obtener información sobre GD y SD, consulte https://www.postgresql .org/docs/current/static/plpython-sharing.html
.
Para verlo en acción sabiendo que los blobs en mi base de datos están almacenados como little endian,
SELECT bytea_to_double_array(decode('efbeaddeefbeadde', 'hex')), encode(double_array_to_bytea(array[-1.1885959257070704E148]), 'hex');
Y la respuesta que obtengo es
bytea_to_double_array | encode
double precision[] | text
-------------------------+------------------
{-1.18859592570707e+148} | efbeaddeefbeadde
donde 'efbeaddeefbeadde'
es 'deadbeefdeadbeef'
en little endian.