43.2. Значения данных#
43.2. Значения данных #
В целом, целью PL/Python является обеспечение "естественного" соответствия между мирами PostgreSQL и Python. Это определяет правила отображения данных, описанные ниже.
43.2.1. Сопоставление типов данных #
Когда вызывается функция 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, преобразуются в тип
strPython (в формате Unicode, как и все строки в Python).Для нескалярных типов данных см. ниже.
Когда функция PL/Python возвращает значение, оно преобразуется в объявленный тип данных возвращаемого значения PostgreSQL следующим образом:
Когда тип возвращаемого значения PostgreSQL является
boolean, возвращаемое значение будет оцениваться на истинность в соответствии с правилами Python. То есть, 0 и пустая строка являются ложными, но заметим, что'f'является true.Когда тип возвращаемого значения PostgreSQL является
bytea, возвращаемое значение будет преобразовано в типbytesPython с использованием соответствующих встроенных функций Python, и результат будет преобразован вbytea.Для всех остальных типов возвращаемых значений PostgreSQL, возвращаемое значение преобразуется в строку с использованием встроенной функции Python
str, и результат передается во входную функцию типа данных PostgreSQL. (Если значение Python является типомfloat, оно преобразуется с использованием встроенной функцииreprвместоstr, чтобы избежать потери точности).Строки автоматически преобразуются в кодировку сервера PostgreSQL при передаче их в PostgreSQL.
Для нескалярных типов данных см. ниже.
Обратите внимание, что логические несоответствия между объявленным типом возвращаемого значения PostgreSQL и типом данных Python фактического возвращаемого объекта не будут отмечены; значение будет преобразовано в любом случае.
43.2.2. Null, None #
Если значение SQL равно null
Если аргумент None передается в функцию, то значение аргумента будет отображаться как None в Python. Например, определение функции pymax, показанное в Раздел 43.1, вернет неправильный ответ для пустых входных данных. Можно добавить STRICT к определению функции, чтобы Tantor BE выполнил что-то более корректно: если передается пустое значение, функция вообще не будет вызываться, а просто автоматически вернет пустой результат. В качестве альтернативы, можно проверить пустые входные данные в теле функции:
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. Это можно сделать независимо от того, является ли функция строгой или нет.
43.2.3. Массивы, cписки #
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)
43.2.4. Составные типы #
Аргументы типа Composite передаются в функцию как отображения 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 );
Композитный результат может быть возвращен в виде:
- Sequence type (a tuple or list, but not a set because it is not indexable)
Возвращаемые объекты последовательности должны иметь такое же количество элементов, как и полей в составном типе результата. Элемент с индексом 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 составной тип или другое измерение массива.
- Mapping (dictionary)
Значение для каждого столбца типа результата извлекается из отображения с именем столбца в качестве ключа. Пример:
CREATE FUNCTION make_pair (name text, value integer) RETURNS named_value AS $$ return { "name": name, "value": value } $$ LANGUAGE plpython3u;Любые дополнительные пары ключ/значение в словаре игнорируются. Отсутствующие ключи считаются ошибками. Для возврата значения SQL NULL для любого столбца вставьте
Noneс соответствующим именем столбца в качестве ключа.- Object (any object providing method
__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);
43.2.5. Функции, возвращающие наборы значений #
A PL/Python функция также может возвращать наборы скалярных или составных типов. Существует несколько способов достижения этого, поскольку возвращаемый объект внутренне преобразуется в итератор. Следующие примеры предполагают, что у нас есть составной тип:
CREATE TYPE greeting AS ( how text, who text );
Результатом запроса может быть набор значений:
- Sequence type (tuple, list, set)
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;
- Iterator (any object providing
__iter__and__next__methods) 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;- Generator (
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);