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, преобразуются в тип
str
Python (в формате Unicode, как и все строки в Python).Для нескалярных типов данных см. ниже.
Когда функция PL/Python возвращает значение, оно преобразуется в объявленный тип данных возвращаемого значения PostgreSQL следующим образом:
Когда тип возвращаемого значения PostgreSQL является
boolean
, возвращаемое значение будет оцениваться на истинность в соответствии с правилами Python. То есть, 0 и пустая строка являются ложными, но заметим, что'f'
является true.Когда тип возвращаемого значения PostgreSQL является
bytea
, возвращаемое значение будет преобразовано в типbytes
Python с использованием соответствующих встроенных функций 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);