Значения данных
Эта страница переведена при помощи нейросети GigaChat.
В общем и целом, цель PL/Python – предоставить «естественное» соответствие между мирами PostgreSQL и Python. Этим определяется выбор правил сопоставления данных, описанных ниже.
Сопоставление типов данных
Когда вызывается функция PL/Python, ее аргументы преобразуются из типа данных PostgreSQL в соответствующий тип Python:
- PostgreSQL
booleanпреобразуется в Pythonbool. - PostgreSQL
smallint,int,bigintиoidпреобразуются в Pythonint. - PostgreSQL
realиdoubleпреобразуются в Pythonfloat. - PostgreSQL
numericпреобразуется в PythonDecimal. Этот тип импортируется из пакетаcdecimal, если он доступен. В противном случае будет использоватьсяdecimal.Decimalиз стандартной библиотеки.cdecimalзначительно быстрее, чемdecimal. Однако в Python 3.3 и вышеcdecimalбыл интегрирован в стандартную библиотеку под именемdecimal, поэтому больше нет никакой разницы. - PostgreSQL
byteaпреобразуется в Pythonbytes. - Все остальные типы данных, включая типы строк символов PostgreSQL, преобразуются в строку Python
str(в Unicode, как и все строки Python). - Для нескалярных типов данных см. ниже.
Когда функция PL/Python возвращает значение, ее возвращаемое значение преобразуется в объявленный тип данных возврата PostgreSQL следующим образом:
-
Когда тип возврата PostgreSQL равен
boolean, возвращаемое значение будет оценено на истинность в соответствии с правилами Python. То есть 0 и пустая строка ложны, а'f'истинно. -
Когда тип возврата PostgreSQL равен
bytea, возвращаемое значение будет преобразовано в Pythonbytesс использованием соответствующих встроенных функций Python, причем результатом будет преобразование вbytea. -
Для всех остальных типов возвращаемых значений PostgreSQL возвращаемое значение преобразуется в строку с использованием встроенной функции Python
str, и результат передается входной функции типа данных PostgreSQL. Если значение Python являетсяfloat, оно преобразуется с помощью встроенного методаreprвместоstr, чтобы избежать потери точности.Строки автоматически преобразуются в кодировку сервера PostgreSQL при передаче в PostgreSQL.
-
Для нескалярных типов данных см. ниже.
Обратите внимание, что логические несоответствия между объявленным типом возвращаемого значения PostgreSQL и фактическим типом возвращаемого объекта Python не отмечаются, значение будет преобразовано в любом случае.
NULL, None
Если значение SQL NULL передается функции, значение аргумента будет отображаться как None в Python. Например, определение функции pymax, показанное в разделе «Функции PL/Python», вернет неправильный ответ для пустых входных значений. Можно было бы добавить STRICT к определению функции, чтобы заставить PostgreSQL делать что-то более разумное: если передается нулевое значение, функция вообще не вызывается, а просто автоматически возвращается нулевой результат. В качестве альтернативы можно проверить наличие нулевых входных данных в теле функции:
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;
Как показано выше, чтобы вернуть значение SQL NULL из функции PL/Python, верните значение None. Это можно сделать независимо от того, является ли функция строгой или нет.
Массивы, Списки
Значения массивов 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 row)
Другие последовательности 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 row)
Составные типы
Аргументы составного типа передаются функции как отображения 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 )
# or alternatively, as list: return [ name, value ]
$$ LANGUAGE plpython3u;Чтобы вернуть SQL
NULLдля любого столбца, вставьтеNoneв соответствующее положение.Когда массив составных типов возвращается, он не может быть возвращен как список, потому что неясно, представляет ли список Python составной тип или другое измерение массива.
-
Сопоставление (словарь) – значение для каждого столбца типа результата извлекается из сопоставления с именем столбца в качестве ключа. Пример:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
return { "name": name, "value": value }
$$ LANGUAGE plpython3u;Любые дополнительные пары ключ/значение словаря игнорируются. Отсутствующие ключи обрабатываются как ошибки. Чтобы вернуть значение SQL
NULLдля любого столбца, вставьте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 также может возвращать наборы скалярных или составных типов. Есть несколько способов добиться этого, потому что возвращаемый объект внутренне преобразуется в итератор. В следующих примерах предполагается, что есть составной тип:
CREATE TYPE greeting AS (
how text,
who text
);
Множество в качестве результата можно возвратить, применив:
-
Последовательность (кортеж, список, набор):
CREATE FUNCTION greet (how text)
RETURNS SETOF greeting
AS $$
# return tuple containing lists as composite types
# all other combinations work also
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;
Функции, возвращающие множество с параметрами 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);