PL/Python 語言模組會自動匯入一個名為 plpy
的 Python 模組。 此模組中的函數和常數可在 Python 程式碼中以 plpy.
的形式使用。foo
plpy
模組提供多個函數來執行資料庫指令
plpy.execute
(query
[, limit
])
使用查詢字串和可選的列數限制引數呼叫 plpy.execute
會導致執行該查詢,並將結果傳回在結果物件中。
如果指定了 limit
且大於零,則 plpy.execute
最多會擷取 limit
列,這與查詢中包含 LIMIT
子句非常相似。 省略 limit
或將其指定為零將不會導致列數限制。
結果物件會模擬列表或字典物件。 可以透過列號和欄位名稱存取結果物件。 例如
rv = plpy.execute("SELECT * FROM my_table", 5)
從 my_table
傳回最多 5 列。 如果 my_table
有一個欄位 my_column
,則可以這樣存取它
foo = rv[i]["my_column"]
傳回的列數可以使用內建的 len
函數取得。
結果物件具有下列其他方法
nrows
()
傳回指令處理的列數。 請注意,這不一定與傳回的列數相同。 例如,UPDATE
指令將設定此值,但不傳回任何列(除非使用 RETURNING
)。
status
()
SPI_execute()
傳回值。
colnames
()
coltypes
()
coltypmods
()
分別傳回欄位名稱列表、欄位類型 OID 列表,以及欄位特定類型修改器的列表。
從未產生結果集的指令(例如,沒有 RETURNING
的 UPDATE
或 DROP TABLE
)的結果物件呼叫這些方法會引發例外。 但是,在包含零列的結果集上使用這些方法是可以的。
__str__
()
定義了標準的 __str__
方法,因此例如可以使用 plpy.debug(rv)
來偵錯查詢執行結果。
結果物件可以修改。
請注意,呼叫 plpy.execute
會導致將整個結果集讀入記憶體中。 僅在確定結果集相對較小時才使用該函數。 如果您不想在擷取大型結果時冒記憶體使用過多的風險,請使用 plpy.cursor
而不是 plpy.execute
。
plpy.prepare
(query
[, argtypes
])
plpy.execute
(plan
[, arguments
[, limit
]])
plpy.prepare
為查詢準備執行計畫。 呼叫時會使用查詢字串和參數類型列表(如果查詢中有參數參照)。 例如
plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", ["text"])
text
是您將為 $1
傳遞的變數類型。 如果您不想將任何參數傳遞給查詢,則第二個引數是可選的。
準備好陳述式後,您可以使用函數 plpy.execute
的變體來執行它
rv = plpy.execute(plan, ["name"], 5)
將計畫作為第一個引數傳遞(而不是查詢字串),並將要替換到查詢中的值列表作為第二個引數傳遞。 如果查詢不需要任何參數,則第二個引數是可選的。 第三個引數是與之前一樣的可選列數限制。
或者,您可以在計畫物件上呼叫 execute
方法
rv = plan.execute(["name"], 5)
查詢參數和結果列欄位會在 PostgreSQL 和 Python 資料類型之間轉換,如 第 44.2 節中所述。
當您使用 PL/Python 模組準備計畫時,它會自動儲存。 閱讀 SPI 文件(第 45 章)以了解這代表什麼。 為了在函數呼叫之間有效地使用它,需要使用其中一個持久儲存字典 SD
或 GD
(請參閱 第 44.3 節)。 例如
CREATE FUNCTION usesavedplan() RETURNS trigger AS $$ if "plan" in SD: plan = SD["plan"] else: plan = plpy.prepare("SELECT 1") SD["plan"] = plan # rest of function $$ LANGUAGE plpython3u;
plpy.cursor
(query
)
plpy.cursor
(plan
[, arguments
])
plpy.cursor
函數接受與 plpy.execute
相同的引數 (除了列數限制),並傳回一個游標物件,允許您以較小的區塊處理大型結果集。如同 plpy.execute
,可以使用查詢字串或預備陳述式物件以及引數列表,或者可以將 cursor
函數作為預備陳述式物件的方法來呼叫。
游標物件提供一個 fetch
方法,它接受一個整數參數並傳回一個結果物件。每次您呼叫 fetch
時,傳回的物件將包含下一批資料列,永遠不大於參數值。一旦所有資料列都被取出,fetch
開始傳回一個空的結果物件。游標物件也提供一個 迭代器介面,一次產生一行,直到所有資料列都被取出。以這種方式取出的資料不會作為結果物件傳回,而是作為字典傳回,每個字典對應到一個單一的結果列。
以下是處理大型表格資料的兩種方式的範例:
CREATE FUNCTION count_odd_iterator() RETURNS integer AS $$ odd = 0 for row in plpy.cursor("select num from largetable"): if row['num'] % 2: odd += 1 return odd $$ LANGUAGE plpython3u; CREATE FUNCTION count_odd_fetch(batch_size integer) RETURNS integer AS $$ odd = 0 cursor = plpy.cursor("select num from largetable") while True: rows = cursor.fetch(batch_size) if not rows: break for row in rows: if row['num'] % 2: odd += 1 return odd $$ LANGUAGE plpython3u; CREATE FUNCTION count_odd_prepared() RETURNS integer AS $$ odd = 0 plan = plpy.prepare("select num from largetable where num % $1 <> 0", ["integer"]) rows = list(plpy.cursor(plan, [2])) # or: = list(plan.cursor([2])) return len(rows) $$ LANGUAGE plpython3u;
游標會自動釋放。但是,如果您想明確釋放游標所持有的所有資源,請使用 close
方法。關閉後,游標就無法再提取資料。
請不要將 plpy.cursor
建立的物件與 Python 資料庫 API 規範所定義的 DB-API 游標混淆。除了名稱之外,它們沒有任何共同之處。
存取資料庫的函數可能會遇到錯誤,這會導致它們中止並引發例外。plpy.execute
和 plpy.prepare
都可能引發 plpy.SPIError
的子類別的實例,預設情況下這將終止函數。此錯誤可以像任何其他 Python 例外一樣處理,使用 try/except
結構。例如:
CREATE FUNCTION try_adding_joe() RETURNS text AS $$ try: plpy.execute("INSERT INTO users(username) VALUES ('joe')") except plpy.SPIError: return "something went wrong" else: return "Joe added" $$ LANGUAGE plpython3u;
引發的例外類別實際對應於導致錯誤的特定條件。請參閱表 A.1,以取得可能條件的列表。模組 plpy.spiexceptions
為每個 PostgreSQL 條件定義一個例外類別,從條件名稱派生其名稱。例如,division_by_zero
變成 DivisionByZero
,unique_violation
變成 UniqueViolation
,fdw_error
變成 FdwError
,依此類推。每個例外類別都繼承自 SPIError
。這種分離使得更容易處理特定錯誤,例如:
CREATE FUNCTION insert_fraction(numerator int, denominator int) RETURNS text AS $$ from plpy import spiexceptions try: plan = plpy.prepare("INSERT INTO fractions (frac) VALUES ($1 / $2)", ["int", "int"]) plpy.execute(plan, [numerator, denominator]) except spiexceptions.DivisionByZero: return "denominator cannot equal zero" except spiexceptions.UniqueViolation: return "already have that fraction" except plpy.SPIError as e: return "other error, SQLSTATE %s" % e.sqlstate else: return "fraction inserted" $$ LANGUAGE plpython3u;
請注意,由於 plpy.spiexceptions
模組中的所有例外都繼承自 SPIError
,因此處理它的 except
子句將捕獲任何資料庫存取錯誤。
作為處理不同錯誤條件的替代方法,您可以捕獲 SPIError
例外,並通過查看例外物件的 sqlstate
屬性來確定 except
區塊內的特定錯誤條件。此屬性是一個字串值,包含 “SQLSTATE” 錯誤碼。此方法提供大致相同的功能:
如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步說明的地方,請使用此表單報告文件問題。