В целом, цель PL/Python заключается в предоставлении «естественного» сопоставления между мирами PostgreSQL и Python. Это лежит в основе правил сопоставления данных, описанных ниже.
При вызове функции на PL/Python её аргументы преобразуются из типа данных PostgreSQL в соответствующий тип Python:
PostgreSQL boolean преобразуется в тип Python bool.
PostgreSQL smallint, int, bigint
и oid преобразуются в тип Python int.
PostgreSQL real и double преобразуются в
Python float.
PostgreSQL numeric преобразуется в
Python Decimal. Этот тип импортируется из
пакета cdecimal если он доступен.
В противном случае
decimal.Decimal из стандартной библиотеки будет
использован. cdecimal значительно быстрее
чем decimal. Начиная с Python 3.3,
однако, cdecimal был интегрирован в
стандартную библиотеку под именем decimal, поэтому
разницы больше нет.
PostgreSQL bytea преобразуется в тип Python bytes.
Все остальные типы данных, включая строковые типы PostgreSQL,
преобразуются в тип Python str (в кодировке Unicode, как и все строки
Python).
Для нескалярных типов данных см. ниже.
Когда функция PL/Python завершает выполнение, возвращаемое значение преобразуется в объявленный тип данных PostgreSQL следующим образом:
Если возвращаемый тип PostgreSQL — boolean, то
возвращаемое значение будет проверяться на истинность согласно
Python правилам. То есть, 0 и пустая строка
трактуются как ложь (false), но, что примечательно, 'f' трактуется как истина (true).
Если возвращаемый тип PostgreSQL — bytea, возвращаемое значение
будет преобразовано в формат Python bytes с использованием соответствующих
встроенных средств Python, а полученный результат будет преобразован в
bytea.
Для всех остальных возвращаемых типов PostgreSQL значение преобразуется
в строку с помощью встроенной функции Python str, после чего
результат передается входной функции соответствующего типа данных PostgreSQL.
(Если значение Python представляет собой float, оно преобразуется с использованием
пакета repr вместо встроенной функции str, чтобы
избежать потери точности.)
Строки автоматически преобразуются в кодировку сервера PostgreSQL при их передаче в PostgreSQL.
Для нескалярных типов данных см. ниже.
Обратите внимание, что логические несоответствия между объявленным типом возвращаемого значения PostgreSQL и типом данных Python фактически возвращаемого объекта не фиксируются; значение будет преобразовано в любом случае.
Если значение NULL в SQL передается в функцию, значение аргумента будет представлено как None в
Python. Например, определение функции pymax
показанное в Раздел 5.9.1 вернет неверный результат для входных данных NULL.
Мы могли бы добавить STRICT в определение функции,
чтобы Digital Q.DataBase сделать поведение более логичным:
если передано значение NULL, функция не будет вызвана вовсе,
а просто автоматически вернет результат NULL. Альтернативный вариант:
проверку на наличие значений NULL можно выполнить в теле функции:
CREATE FUNCTION pymax (a integer, b integer)
RETURNS integer
AS $$
if (a is None) or (b is None):
return None
if a > b:
return a
return b
$$ LANGUAGE plpython3u;
Как показано выше, чтобы вернуть значение NULL в SQL из функции PL/Python, следует возвращать значение None. Это можно сделать независимо от того, помечена ли функция как STRICT или нет.
Значения массивов SQL передаются в PL/Python как список Python. Чтобы вернуть значение массива SQL из функции PL/Python, необходимо вернуть список Python:
CREATE FUNCTION return_arr()
RETURNS int[]
AS $$
return [1, 2, 3, 4, 5]
$$ LANGUAGE plpython3u;
SELECT return_arr();
return_arr
-------------
{1,2,3,4,5}
(1 row)
Многомерные массивы передаются в PL/Python как вложенные списки Python. Например, двумерный массив — это список списков. При возврате многомерного массива SQL из функции PL/Python внутренние списки на каждом уровне должны иметь одинаковый размер. Например:
CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
plpy.info(x, type(x))
return x
$$ LANGUAGE plpython3u;
SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]);
INFO: ([[1, 2, 3], [4, 5, 6]], <type 'list'>)
test_type_conversion_array_int4
---------------------------------
{{1,2,3},{4,5,6}}
(1 строка)
Другие последовательности Python, такие как кортежи, также поддерживаются для обратной совместимости с PostgreSQL версий 9.6 и ниже, в которых многомерные массивы не поддерживались. Однако они всегда обрабатываются как одномерные массивы, так как в противном случае они неотличимы от составных типов. По этой же причине, когда составной тип используется в многомерном массиве, он должен быть представлен кортежем, а не списком.
Обратите внимание, что в Python строки являются последовательностями, что может привести к нежелательным эффектам, знакомым разработчикам на Python:
CREATE FUNCTION return_str_arr()
RETURNS varchar[]
AS $$
return "hello"
$$ LANGUAGE plpython3u;
SELECT return_str_arr();
return_str_arr
----------------
{h,e,l,l,o}
(1 строка)
Аргументы составных типов передаются функции в виде отображений (mappings) Python. Именами элементов в отображении являются имена атрибутов составного типа. Если атрибут в переданной строке имеет значение NULL, он принимает значение
None в отображении. Вот пример:
CREATE TABLE employee (
name text,
salary integer,
age integer
);
CREATE FUNCTION overpaid (e employee)
RETURNS boolean
AS $$
if e["salary"] > 200000:
return True
if (e["age"] < 30) and (e["salary"] > 100000):
return True
return False
$$ LANGUAGE plpython3u;
Существует несколько способов возврата строк или составных типов из функции на языке Python. В следующих примерах предполагается, что созданы следующие объекты:
CREATE TYPE named_value AS ( name text, value integer );
Составной результат может быть возвращен в виде:
Возвращаемые объекты последовательности должны содержать то же количество элементов, что и количество полей в составном типе результата. Элемент с индексом 0 присваивается первому полю составного типа, элемент с индексом 1 — второму и так далее. Например: Пример:
CREATE FUNCTION make_pair (name text, value integer) RETURNS named_value AS $$ return ( name, value ) # или, в качестве альтернативы, как список: return [ name, value ] $$ LANGUAGE plpython3u;
Чтобы вернуть SQL NULL для любого столбца, вставьте None None
в соответствующую позицию.
Если возвращается массив составных типов, он не может быть возвращен в виде списка, поскольку невозможно однозначно определить, представляет ли список Python составной тип или другую размерность массива.
Значение для каждого столбца результирующего типа извлекается из отображения с использованием имени столбца в качестве ключа. Пример:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
return { "name": name, "value": value }
$$ LANGUAGE plpython3u;
Любые лишние пары ключ/значение в словаре игнорируются. Отсутствие ключей
считается ошибкой.
Чтобы вернуть значение NULL в SQL для любого столбца, вставьте None
None с соответствующим именем столбца в качестве ключа.
__getattr__)Этот механизм работает так же, как и отображение. Пример:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
class named_value:
def __init__ (self, n, v):
self.name = n
self.value = v
return named_value(name, value)
# or simply
class nv: pass
nv.name = name
nv.value = value
return nv
$$ LANGUAGE plpython3u;
Функции с OUT параметрами также поддерживаются. Например:
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$ return (1, 2) $$ LANGUAGE plpython3u; SELECT * FROM multiout_simple();
Выходные параметры процедур передаются обратно тем же способом. Например:
CREATE PROCEDURE python_triple(INOUT a integer, INOUT b integer) AS $$ return (a * 3, b * 3) $$ LANGUAGE plpython3u; CALL python_triple(5, 10);
PL/Python- PL/Python функция также может возвращать наборы скалярных или составных типов. Существует несколько способов добиться этого, так как возвращаемый объект внутри преобразуется в итератор. В следующих примерах предполагается наличие составного типа:
CREATE TYPE greeting AS ( how text, who text );
Результат в виде набора может быть возвращён из:
CREATE FUNCTION greet (how text) RETURNS SETOF greeting AS $$ # возвращает кортеж, содержащий списки как составные типы # все остальные комбинации также работают return ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] ) $$ LANGUAGE plpython3u;
__iter__ и
__next__ методы)
CREATE FUNCTION greet (how text)
RETURNS SETOF greeting
AS $$
class producer:
def __init__ (self, how, who):
self.how = how
self.who = who
self.ndx = -1
def __iter__ (self):
return self
def __next__(self):
self.ndx += 1
if self.ndx == len(self.who):
raise StopIteration
return ( self.how, self.who[self.ndx] )
return producer(how, [ "World", "PostgreSQL", "PL/Python" ])
$$ LANGUAGE plpython3u;
yield)
CREATE FUNCTION greet (how text)
RETURNS SETOF greeting
AS $$
for who in [ "World", "PostgreSQL", "PL/Python" ]:
yield ( how, who )
$$ LANGUAGE plpython3u;
Функции, возвращающие набор (set-returning functions), с OUT параметрами
(использующие RETURNS SETOF record) также
поддерживаются. Например:
CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$ return [(1, 2)] * n $$ LANGUAGE plpython3u; SELECT * FROM multiout_simple_setof(3);