PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Converti byte in doppia precisione in PostgreSQL

Ok, ho trovato una risposta. In PostgreSQL, puoi scrivere funzioni usando Python. Per abilitare l'uso di Python, devi installare la versione specifica di Python necessaria per la tua installazione di PostgreSQL e averla disponibile nella variabile d'ambiente PATH. Puoi trovare la versione di Python necessaria per la tua installazione di PostgreSQL guardando le note di installazione. Attualmente sto usando PostgreSQL 9.6.5 su Windows e richiede Python 3.3. Inizialmente ho provato l'ultimo Python 3.6, ma non ha funzionato. Ho optato per l'ultimo Python 3.3 per Windows, che è 3.3.5.

Dopo aver installato Python, lo abiliti in PostgreSQL eseguendo CREATE EXTENSION plpython3u; nel tuo database come documentato qui https://www.postgresql.org/docs /corrente/statico/plpython.html . Da lì, puoi scrivere qualsiasi funzione con corpi Python.

Per il mio caso specifico da convertire da bytea a double precision[] e ritorno, ho scritto le seguenti funzioni:

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$;

Nel mio caso, tutti i doppi sono memorizzati in little endian, quindi uso < . Ho anche memorizzato nella cache l'importazione della struct modulo nel dizionario globale come descritto in https://stackoverflow.com/a/15025425/5274457 . Ho usato GD invece di SD perché voglio che l'importazione sia disponibile in altre funzioni che potrei scrivere. Per informazioni su GD e SD, vedere https://www.postgresql .org/docs/current/static/plpython-sharing.html .

Per vederlo in azione sapendo che i BLOB nel mio database sono archiviati come little endian,

SELECT bytea_to_double_array(decode('efbeaddeefbeadde', 'hex')), encode(double_array_to_bytea(array[-1.1885959257070704E148]), 'hex');

E la risposta che ottengo è

bytea_to_double_array    | encode
double precision[]       | text
-------------------------+------------------
{-1.18859592570707e+148} | efbeaddeefbeadde

dove 'efbeaddeefbeadde' è 'deadbeefdeadbeef' in little endian.