Перейти к основному содержимому

Значения данных

примечание

Эта страница переведена при помощи нейросети GigaChat.

В общем и целом, цель 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 и пустая строка ложны, а 'f' истинно.

  • Когда тип возврата PostgreSQL равен bytea, возвращаемое значение будет преобразовано в Python bytes с использованием соответствующих встроенных функций 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);