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 異常,並在 except 塊中透過檢視異常物件的 sqlstate 屬性來確定特定的錯誤條件。此屬性是一個字串值,包含“SQLSTATE”錯誤程式碼。此方法提供了大致相同的功能:
如果您在文件中發現任何不正確的內容、與您對特定功能的體驗不符的內容或需要進一步說明的內容,請使用 此表單報告文件問題。