Skip to main content

Как активировать PL/Python, примеры функции и процедуры

Чтобы использовать PL/Python, необходимо, чтобы модуль Python был установлен в вашей операционной системе для вашей версии PostgreSQL (например, пакет postgresql-plpython3 в Linux), после чего его можно включить в нужной базе данных.

1. Активация PL/Python

Активировать расширение нужно в целевой базе данных от имени суперпользователя (postgres):

SQL
CREATE EXTENSION IF NOT EXISTS plpython3u;
Важная деталь: Буква u на конце расширения означает untrusted (недоверенный). Это значит, что функции на PL/Python могут обращаться к файловой системе сервера, сети и операционной системе, поэтому создавать функции на PL/Python может только суперпользователь СУБД.

2. Пример функции (Function)

Функции в PostgreSQL возвращают значение. В PL/Python вы можете импортировать любые сторонние библиотеки Python (например, json, math, requests, pandas и др.).

Пример функции для парсинга и валидации JSON-строки с расчетом итоговой стоимости:

SQL
CREATE OR REPLACE FUNCTION calculate_cart_total(cart_json text)
RETURNS numeric AS $$
    import json

    try:
        data = json.loads(cart_json)
        items = data.get("items", [])
        
        total = 0.0
        for item in items:
            price = item.get("price", 0)
            quantity = item.get("quantity", 1)
            total += price * quantity
            
        return round(total, 2)
    except Exception as e:
        # raise_notice или log позволяют отправлять сообщения в клиент/лог базы
        plpy.notice(f"Ошибка при обработке JSON: {e}")
        return 0.0
$$ LANGUAGE plpython3u;
Вызов функции:

SQL
SELECT calculate_cart_total('{"items": [{"price": 100.5, "quantity": 2}, {"price": 50.0, "quantity": 1}]}');
-- Вернет: 251.00

3. Пример процедуры (Procedure)

Процедуры в PostgreSQL не возвращают результат и поддерживают управление транзакциями (plpy.commit(), plpy.rollback()).

Специальный модуль plpy внутри PL/Python позволяет выполнять SQL-запросы внутри базы.

Пример процедуры, которая находит устаревшие записи, отправляет их во внешнюю систему (имитация) и удаляет их:

SQL
CREATE OR REPLACE PROCEDURE cleanup_old_logs(days_old int)
AS $$
    import time

    # Выполняем SQL-запрос к БД с помощью plpy.execute
    plan = plpy.prepare(
        "SELECT id, message FROM system_logs WHERE created_at < NOW() - ($1 || ' days')::INTERVAL",
        ["int"]
    )
    result = plpy.execute(plan, [days_old])

    plpy.info(f"Найдено записей для удаления: {len(result)}")

    if len(result) > 0:
        # Логика обработки записей на Python
        for row in result:
            log_id = row["id"]
            # Здесь можно вызвать внешний API, сохранить резервную копию и т.д.

        # Удаление записей
        delete_plan = plpy.prepare(
            "DELETE FROM system_logs WHERE created_at < NOW() - ($1 || ' days')::INTERVAL",
            ["int"]
        )
        plpy.execute(delete_plan, [days_old])
        
        # Фиксация изменений
        plpy.commit()
$$ LANGUAGE plpython3u;
Вызов процедуры:

SQL
CALL cleanup_old_logs(30);

Дополнительные возможности plpy

Внутри PL/Python вам автоматически доступен встроенный объект plpy:

  • plpy.execute("SELECT ...") — выполнение произвольного SQL-запроса.

  • plpy.prepare(query, [types]) — подготовка SQL-запроса для многократного выполнения.

  • plpy.notice(msg), plpy.info(msg), plpy.warning(msg) — вывод сообщений пользователю.

  • plpy.error(msg) — генерация исключения, отменяющего транзакцию.

Возвращают ли функции PL/Python наборы строк (recordsets) которые можно использовать в SQL-запросах?