Вообще говоря, цель исполнителя PL/Python — обеспечить «естественное» соответствие между мирами PostgreSQL и Python. Этим объясняется выбор правил сопоставления данных, описанных ниже.
Когда вызывается функция PL/Python, её аргументы преобразуются из типа PostgreSQL в соответствующий тип Python по таким правилам:
Тип PostgreSQL boolean
преобразуется в bool
языка Python.
Типы PostgreSQL smallint
и int
преобразуются в тип int
языка Python. Типы PostgreSQL bigint
и oid
становятся типами long
в Python 2 и int
в Python 3.
Типы PostgreSQL real
и double
преобразуются в тип float
языка Python.
Тип PostgreSQL numeric
преобразуется в Decimal
среды Python. Этот тип импортируется из пакета cdecimal
, при его наличии. В противном случае используется decimal.Decimal
из стандартной библиотеки. Тип cdecimal
работает значительно быстрее, чем decimal
. Однако в Python версии 3.3 и выше тип cdecimal
включается в стандартную библиотеку под именем decimal
, так что теперь этого различия нет.
Тип PostgreSQL bytea
становится типом str
в Python 2 и bytes
в Python 3. В Python 2 такую строку следует воспринимать как последовательность байт без какой-либо определённой кодировки символов.
Все другие типы данных, включая типы символьных строк PostgreSQL, преобразуются в тип str
языка Python. В Python 2 эта строка будет передаваться в кодировке сервера PostgreSQL; в Python 3 это будет строка в Unicode, как и все строки.
Информация о нескалярных типах данных приведена ниже.
При завершении функции PL/Python её значение результата преобразуется в тип данных, объявленный как тип результата в PostgreSQL, следующим образом:
Когда тип результата функции в PostgreSQL — boolean
, возвращаемое значение приводится к логическому типу по правилам, принятым в Python. То есть false будет возвращено для 0 и пустой строки, но, обратите внимание, для 'f'
будет возвращено true.
Когда тип результата функции PostgreSQL — bytea
, возвращаемое значение будет преобразовано в строку (Python 2) или набор байт (Python 3), используя встроенные средства Python, а затем будет приведено к типу bytea
.
Для всех других типов результата PostgreSQL возвращаемое значение преобразуется в строку с помощью встроенной в Python функции str
, и полученная строка передаётся функции ввода типа данных PostgreSQL. (Если значение в Python имеет тип float
, оно преобразуется встроенной функцией repr
, а не str
, для недопущения потери точности.)
Из кода Python 2 строки должны передаваться в PostgreSQL в кодировке сервера PostgreSQL. При передаче строки, неприемлемой для текущей кодировки сервера, возникает ошибка, но не все несоответствия кодировки могут быть выявлены, так что с некорректной кодировкой всё же могут быть получены нечитаемые строки. Строки Unicode переводятся в нужную кодировку автоматически, так что использовать их может быть безопаснее и удобнее. В Python 3 все строки имеют кодировку Unicode.
Информация о нескалярных типах данных приведена ниже.
Заметьте, что логические несоответствия между объявленным в PostgreSQL типом результата и типом фактически возвращаемого объекта Python игнорируются — значение преобразуется в любом случае.
Если функции передаётся значение SQL NULL, в Python значением этого аргумента будет None
. Например, функция pymax
, определённая как показано в Раздел 45.2, возвратит неверный ответ, получив аргументы NULL. Мы могли бы добавить указание STRICT
в определение функции, чтобы PostgreSQL поступал немного разумнее: при передаче значения 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 plpythonu;
Как показано выше, чтобы выдать из функции PL/Python значение SQL NULL, нужно вернуть значение None
. Это можно сделать и в строгой, и в нестрогой функции.
Значения массивов SQL передаются в PL/Python в виде списка Python. Чтобы вернуть значение массива SQL из функции PL/Python, возвратите список Python:
CREATE FUNCTION return_arr() RETURNS int[] AS $$ return [1, 2, 3, 4, 5] $$ LANGUAGE plpythonu; 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 plpythonu; 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 plpythonu; 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 plpythonu;
Возвратить составной тип или строку таблицы из функции 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 plpythonu;
Чтобы выдать SQL NULL для какого-нибудь столбца, вставьте в соответствующую позицию None
.
Когда возвращается массив составных значений, его нельзя представить в виде списка, так как невозможно однозначно определить, представляет ли список Python составной тип или ещё одну размерность массива.
Значение столбца результата получается из сопоставления, в котором ключом является имя столбца. Например:
CREATE FUNCTION make_pair (name text, value integer) RETURNS named_value AS $$ return { "name": name, "value": value } $$ LANGUAGE plpythonu;
Любые дополнительные пары ключ/значение в словаре игнорируются, а отсутствие нужных ключей считается ошибкой. Чтобы выдать 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) # или просто class nv: pass nv.name = name nv.value = value return nv $$ LANGUAGE plpythonu;
Также поддерживаются функции с параметрами OUT
(выходными). Например:
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$ return (1, 2) $$ LANGUAGE plpythonu; SELECT * FROM multiout_simple();
Выходные параметры процедуры выдаются таким же образом. Например:
CREATE PROCEDURE python_triple(INOUT a integer, INOUT b integer) AS $$ return (a * 3, b * 3) $$ LANGUAGE plpythonu; 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 ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] ) $$ LANGUAGE plpythonu;
__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 plpythonu;
yield
)
CREATE FUNCTION greet (how text) RETURNS SETOF greeting AS $$ for who in [ "World", "PostgreSQL", "PL/Python" ]: yield ( how, who ) $$ LANGUAGE plpythonu;
Также поддерживаются функции, возвращающие множества, с параметрами OUT
(объявленные с RETURNS SETOF record
). Например:
CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$ return [(1, 2)] * n $$ LANGUAGE plpythonu; SELECT * FROM multiout_simple_setof(3);