Ok, našel jsem odpověď. V PostgreSQL můžete psát funkce pomocí Pythonu. Abyste mohli používat Python, musíte nainstalovat konkrétní verzi Pythonu potřebnou pro vaši instalaci PostgreSQL a mít ji k dispozici v proměnné prostředí PATH. Jakou verzi Pythonu vaše instalace PostgreSQL potřebuje, zjistíte v poznámkách k instalaci. V současné době používám PostgreSQL 9.6.5 na Windows a vyžaduje Python 3.3. Původně jsem zkoušel nejnovější Python 3.6, ale nefungovalo to. Spokojil jsem se s nejnovějším Pythonem 3.3 pro Windows, což je 3.3.5.
Po instalaci Pythonu jej povolíte v PostgreSQL spuštěním CREATE EXTENSION plpython3u;
ve vaší databázi, jak je zdokumentováno zde https://www.postgresql.org/docs /current/static/plpython.html
. Odtud můžete psát libovolnou funkci s těly Pythonu.
Pro můj konkrétní případ převod z bytea
na double precision[]
a zpět jsem napsal následující funkce:
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$;
V mém případě jsou všechny dvojky uloženy v little endian, takže používám <
. Také ukládám do mezipaměti import struct
modulu v globálním slovníku, jak je popsáno v https://stackoverflow.com/a/15025425/5274457 . Použil jsem GD místo SD, protože chci, aby byl import dostupný v jiných funkcích, které mohu psát. Informace o GD a SD najdete na https://www.postgresql .org/docs/current/static/plpython-sharing.html
.
Abych to viděl v akci, když vím, že bloby v mé databázi jsou uloženy jako little endian,
SELECT bytea_to_double_array(decode('efbeaddeefbeadde', 'hex')), encode(double_array_to_bytea(array[-1.1885959257070704E148]), 'hex');
A odpověď, kterou dostávám, je
bytea_to_double_array | encode
double precision[] | text
-------------------------+------------------
{-1.18859592570707e+148} | efbeaddeefbeadde
kde 'efbeaddeefbeadde'
je 'deadbeefdeadbeef'
v little endian.