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

Примечание

Эта страница переведена при помощи нейросети 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);