支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0

44.2. 資料值 #

一般而言,PL/Python 的目標是在 PostgreSQL 和 Python 世界之間提供一個「自然」的映射。 這影響了下面描述的資料映射規則。

44.2.1. 資料類型映射 #

當呼叫 PL/Python 函數時,它的引數會從它們的 PostgreSQL 資料類型轉換為對應的 Python 類型

  • PostgreSQL boolean 會轉換為 Python bool

  • PostgreSQL smallintintbigintoid 會轉換為 Python int

  • PostgreSQL realdouble 會轉換為 Python float

  • PostgreSQL numeric 會轉換為 Python Decimal。如果 cdecimal 封裝可用,則會從該封裝匯入此類型。否則,將使用標準程式庫中的 decimal.Decimalcdecimaldecimal 快很多。但是,在 Python 3.3 及更高版本中,cdecimal 已整合到標準程式庫中,名稱為 decimal,因此不再有任何差異。

  • PostgreSQL bytea 會轉換為 Python bytes

  • 所有其他資料類型,包括 PostgreSQL 字元串類型,都會轉換為 Python str(在 Unicode 中,就像所有 Python 字串一樣)。

  • 對於非純量資料類型,請參閱下文。

當 PL/Python 函數傳回時,其傳回值會轉換為函數宣告的 PostgreSQL 傳回資料類型,如下所示

  • 當 PostgreSQL 傳回類型為 boolean 時,將根據Python規則評估傳回值的真偽。 也就是說,0 和空字串為 false,但值得注意的是 'f' 為 true。

  • 當 PostgreSQL 傳回類型為 bytea 時,傳回值將使用各自的 Python 內建函數轉換為 Python bytes,並且結果將轉換為 bytea

  • 對於所有其他 PostgreSQL 傳回類型,傳回值會使用 Python 內建 str 轉換為字串,並且結果會傳遞到 PostgreSQL 資料類型的輸入函數。(如果 Python 值為 float,則會使用 repr 內建函數而不是 str 進行轉換,以避免遺失精確度。)

    當字串傳遞到 PostgreSQL 時,它們會自動轉換為 PostgreSQL 伺服器編碼。

  • 對於非純量資料類型,請參閱下文。

請注意,宣告的 PostgreSQL 傳回類型和實際傳回物件的 Python 資料類型之間的邏輯不匹配不會被標記;無論如何都會轉換該值。

44.2.2. Null, None #

如果將 SQL null 值傳遞給函數,則引數值將在 Python 中顯示為 None。例如,第 44.1 節中顯示的 pymax 函數定義將針對 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 plpython3u;

如上所示,要從 PL/Python 函數傳回 SQL null 值,請傳回值 None。無論函數是否嚴格,都可以執行此操作。

44.2.3. 陣列、列表 #

SQL 陣列值會作為 Python 列表傳遞到 PL/Python 中。要從 PL/Python 函數傳回 SQL 陣列值,請傳回 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)

多維陣列會作為巢狀 Python 列表傳遞到 PL/Python 中。 例如,二維陣列是一個列表的列表。 當從 PL/Python 函數傳回多維 SQL 陣列時,每個層級的內部列表的大小都必須相同。 例如

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)

44.2.4. 複合類型 #

複合類型引數會作為 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);

44.2.5. 傳回集合的函式 #

PL/Python 函式也可以傳回純量或複合類型的集合。有多種方法可以實現這一點,因為傳回的物件會在內部轉換為迭代器。以下範例假設我們有複合類型:

CREATE TYPE greeting AS (
  how text,
  who text
);

可以從以下項目傳回集合結果:

序列類型(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;
迭代器(任何提供 __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);

提交更正

如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的地方,請使用此表格來報告文件問題。