PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Converter bytea para precisão dupla no PostgreSQL


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.