Языковой модуль PL/Python автоматически импортирует Python-модуль под названием plpy. Функции и константы в
этом модуле доступны вам в Python-коде как
plpy..
foo
Модуль plpy предоставляет несколько функций для выполнения
команд базы данных:
plpy.выполнить(запрос [, limit])
Вызов plpy.execute со строкой запроса и необязательным аргументом ограничения количества строк приводит к выполнению этого запроса и возврату результата в виде объекта результата.
Если limit указан и больше
нуля, то plpy.execute извлекает не
более limit строк, так же, как если бы запрос
содержал LIMIT
предложение. Пропуск limit или его указание как
нуля означает отсутствие ограничения на количество строк.
Объект результата имитирует объект списка или словаря. К объекту результата можно обращаться по номеру строки и имени столбца. Например:
rv = plpy.execute("SELECT * FROM my_table", 5)
возвращает до 5 строк из my_table. Если
my_table имеет столбец
my_column, доступ к нему осуществляется следующим образом:
foo = rv[i]["my_column"]
Количество возвращенных строк можно получить с помощью встроенной
len функции.
Объект результата содержит следующие дополнительные методы:
nrows()
Возвращает количество строк, обработанных командой. Обратите внимание, что это значение
не обязательно совпадает с количеством возвращенных строк. Например,
команда UPDATE установит это значение, но
не вернет строк (если только не RETURNING используется).
статус()
Данный SPI_execute() возвращаемое значение.
colnames()coltypes()coltypmods()Возвращает список имен столбцов, список OID типов столбцов и список соответствующих модификаторов типов для данных столбцов.
Данные методы генерируют исключение при вызове для объекта результата
команды, которая не возвращает результирующий набор, например,
UPDATE без RETURNING, или
DROP TABLE. Однако эти методы можно использовать для
результирующего набора, содержащего ноль строк.
__str__()
Стандартный __str__ метод определен таким образом, что он
можно, например, выполнять отладку результатов выполнения запроса
с помощью plpy.debug(rv).
Объект результата можно изменять.
Обратите внимание, что вызов plpy.execute приведет к загрузке всего результирующего набора в память. Используйте эту функцию только в том случае, если вы уверены, что результирующий набор будет относительно небольшим. Если вы хотите избежать
риска чрезмерного потребления памяти при получении больших выборок,
используйте plpy.cursor вместо того чтобы plpy.execute.
plpy.prepare(запрос [, argtypes])plpy.выполнить(plan [, аргументы [, limit]])
plpy.prepare подготавливает план выполнения запроса. Функция вызывается со строкой запроса и списком типов параметров,
если в запросе используются ссылки на параметры. Например:
plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", ["text"])
text — это тип переменной, которую вы будете передавать
для $1. Второй аргумент является необязательным, если вы не планируете передавать параметры в запрос.
После подготовки оператора (prepared statement) используйте вариант функции plpy.execute для его выполнения:
rv = plpy.execute(plan, ["name"], 5)
Передайте подготовленный план в качестве первого аргумента (вместо строки запроса), а список значений для подстановки в запрос — в качестве второго аргумента. Второй аргумент является необязательным, если запрос не ожидает параметров. Третий аргумент, как и прежде, позволяет ограничить количество возвращаемых строк.
Кроме того, вы можете вызвать выполнить метод объекта
plan:
rv = plan.execute(["name"], 5)
Преобразование параметров запроса и полей результирующих строк между типами данных PostgreSQL и Python описано в Раздел 5.9.2.
При подготовке плана выполнения с использованием модуля PL/Python он сохраняется автоматически. Обратитесь к документации по SPI (Глава 5.10) за описанием того, что это означает. Для эффективного использования этого механизма между вызовами функций необходимо использовать один из словарей постоянного хранения SD или GD (см.
Раздел 5.9.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.курсор(запрос)plpy.курсор(plan [, аргументы])
Функция plpy.cursor принимает те же аргументы,
что и plpy.execute (за исключением ограничения количества строк) и возвращает
объект курсора, который позволяет обрабатывать большие результирующие наборы
частями. Как и в случае с plpy.execute, можно использовать либо строку запроса либо объект плана вместе со списком аргументов, либо курсор функцию можно вызвать как метод объекта плана.
Объект курсора предоставляет 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 с
курсорами DB-API, определенными в
пакета Python
спецификации Database 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 "что-то пошло не так"
else:
return "Джо добавлен"
$$ LANGUAGE plpython3u;
Фактический класс возбуждаемого исключения соответствует конкретному условию, вызвавшему ошибку. Обратитесь к разделу Таблица 8.1.1 за списком возможных
условий. Модуль
plpy.spiexceptions определяет класс исключения
для каждого Digital Q.DataBase условия, формируя их имена на основе названия условия. Например, 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 "знаменатель не может быть равен нулю"
except spiexceptions.UniqueViolation:
return "такая дробь уже существует"
except plpy.SPIError as e:
return "другая ошибка, SQLSTATE %s" % e.sqlstate
else:
return "дробь добавлена"
$$ LANGUAGE plpython3u;
Обратите внимание: так как все исключения
модуля plpy.spiexceptions наследуются
от SPIError, блок except
, обрабатывающий их, будет перехватывать любую ошибку доступа к базе данных.
В качестве альтернативного способа обработки различных ошибочных ситуаций вы можете перехватить SPIError исключение и определить
конкретное условие ошибки внутри except
блока, обратившись к атрибуту sqlstate объекта
исключения. Этот атрибут является строковым значением, содержащим
код ошибки «SQLSTATE» error code. Данный подход обеспечивает примерно ту же функциональность