Pronto, encontrei uma resposta. No PostgreSQL, você pode escrever funções usando Python. Para habilitar o uso do Python, você deve instalar a versão específica do Python necessária para sua instalação do PostgreSQL e disponibilizá-la na variável de ambiente PATH. Você pode descobrir qual versão do Python sua instalação do PostgreSQL precisa observando as notas de instalação. Atualmente, estou usando o PostgreSQL 9.6.5 no Windows e ele chama o Python 3.3. Inicialmente, tentei o Python 3.6 mais recente, mas não funcionou. Acertei com o mais recente Python 3.3 para Windows, que é 3.3.5.
Após instalar o Python, você o habilita no PostgreSQL executando
CREATE EXTENSION plpython3u;
em seu banco de dados conforme documentado aqui https://www.postgresql.org/docs /current/static/plpython.html
. A partir daí, você pode escrever qualquer função com corpos Python. Para o meu caso específico para converter de
bytea
para double precision[]
e de volta, escrevi as seguintes funções: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$;
No meu caso, todos os doubles são armazenados em little endian, então eu uso
<
. Também armazeno em cache a importação do struct
módulo no dicionário global conforme descrito em https://stackoverflow.com/a/15025425/5274457 . Eu usei GD em vez de SD porque quero a importação disponível em outras funções que eu possa escrever. Para obter informações sobre GD e SD, consulte https://www.postgresql .org/docs/current/static/plpython-sharing.html
. Para vê-lo em ação, sabendo que os blobs no meu banco de dados são armazenados como little endian,
SELECT bytea_to_double_array(decode('efbeaddeefbeadde', 'hex')), encode(double_array_to_bytea(array[-1.1885959257070704E148]), 'hex');
E a resposta que recebo é
bytea_to_double_array | encode
double precision[] | text
-------------------------+------------------
{-1.18859592570707e+148} | efbeaddeefbeadde
onde
'efbeaddeefbeadde'
é 'deadbeefdeadbeef'
em little endian.