PGSQL 05: Расширения

Описание:

Сегодня мы с вами узнаем, что такое расширения (extensions). Как их устанавливать? Как ими управлять?

Что часто говорят, когда вспоминают плюсы PostgreSQL?

  • Система с открытым исходным кодом;
  • поддержка БД неограниченного размера;
  • мощные и надежные механизмы транзакций и репликации;
  • расширяемая система встроенных языков программирования и поддержка загрузки C-совместимых модулей;
  • наследование;
  • легкая расширяемость, заложенная в архитектуру самой системы.

Так вот, как раз за легкую расширяемость и отвечают расширения. Давайте посмотрим, зачем реализован такой механизм, и узнаем, как его рационально использовать.

С самого начала предполагалось, что PostgreSQL как база данных будет расширяться. Под этим понимается, что в нем можно:

  • встраивать функции;
  • встраивать языки программирования;
  • встраивать специальные типы данных;
  • создавать операторы для работы с функциями и новыми типами данных;
  • создавать новые типы индексов;
  • создавать обертки для работы с внешними источниками данных.

И для того чтобы творить все эти улучшения, не требуется вносить какие-либо изменения в код самого сервера. Как раз для этого и реализован механизм расширений.

Общая архитектура:

В большинстве случаев для расширения возможностей системы PostgreSQL необходимо создать несколько разнообразных объектов базы данных, например, описания типов, набор функций и операторов. А для того чтобы управлять этой логически связанной группой объектов, их и упаковывают в расширения (extension). Этот подход не нов и много где встречается.

Если разработанное кем-то расширение находит в сообществе широкий спрос, разработчики могут включить его код в дистрибутив самого сервера в качестве расширения (директория - contrib), а если и там оно будет сильно востребовано - может перекочевать в ядро. И многие популярные расширения уже прошли по этому пути.

Некоторые расширения входят в состав основной распространяемой версии системы PostgreSQL, но не подключаются автоматически при ее установке. Для их подключения достаточно выполнить команду CREATE EXTENSION, указав имя расширения в качестве аргумента.

Но не нужно забывать, что помимо улучшений и расширения функционала этот же механизм может принести с собой и некую долю хаоса:

  • нужно следить, какие расширения стоят, обновлять их версии, переносить данные из них;
  • нужно проверять источники (на предмет закладок и прочих требований безопасности), да и просто на корректность кода, чтобы не поломать существующий функционал.

Хорошо написанное расширение добавит функционал в систему, а плохо или небрежно написанное — может её убить.

Механизм расширений сам по себе не добавляет новые возможности, однако позволяет организовывать модули расширения, описывать действия, необходимые для смены версий расширения, обеспечивает согласованную обработку объектов, входящих в расширение, при создании резервных копий и выполнении других административных действий.

Если в общих чертах, то:

  • нельзя удалить какой-либо компонент расширения по отдельности;
  • нужен механизм обновления версий расширения;
  • pg_dump должен корректно работать и понимать, какие объекты являются частью расширений.

Для системы PostgreSQL каждое расширение описывается.

Где брать расширения?

Традиционно — это каталог /contrib. В нем собраны расширения, которые поставляются вместе с PostgreSQL, отдельно их можно скачать с postgresql.org (их поддерживает команда разработчиков PostgreSQL). pgxn.org — сеть расширений для PostgreSQL по образу и подобию аналогичной сети для PERL. GitHub.com — тоже никто не отменял. В общем, источников для поиска достаточно много. А можно разработать собственное расширение.

Как установить расширение?

Для управления расширениями в PostgreSQL используются команды SQL. Так, загрузка объектов расширения в базу данных выполняется при создании расширения (CREATE EXTENSION). Переход на новую версию — ALTER EXTENSION. А удалить расширения со всеми его объектами можно командой DROP EXTENSION. Не требуется разрабатывать отдельный uninstall скрипт. Для работы этих команд в составе расширений должны быть специальные файлы.

  1. Управляющий конфигурационный файл, который определяет свойства расширения.
  2. Файл, содержащий операторы SQL, которые создают или модифицируют объекты базы данных, входящие в расширение.

Кроме этого, в состав расширения могут входить и другие файлы, например, объектный код функций, написанных на процедурных языках, требующих компиляции, файлы *.sql для версионной миграции этого расширения и другие. Но, с точки зрения управления расширениями, такие файлы не важны.

При выполнении команды CREATE EXTENSION механизм расширений проверяет наличие управляющего файла в каталоге SHAREDIR/extension. Расположение SHAREDIR можно посмотреть командой:

$ pg_config --sharedir

Имя управляющего файла состоит из имени расширения, к которому добавляется «.control». Управляющий файл имеет формат конфигурационных файлов PostgreSQL и состоит из пар «ключ = значение».

Помимо управляющего файла требуется еще файл SQL с командами на создание объектов БД. Имя файла SQL зависит от устанавливаемой версии расширения. Ее можно явно указать в параметре VERSION команды CREATE EXTENSION. По умолчанию будет использоваться версия из параметра default_version управляющего файла. Имя файла SQL строится по шаблону «имя--версия.sql», где версия не обязательно должна состоять из цифр. Она может включать и другие символы (кроме «--» , а также «-» в начале или в конце). Список доступных версий расширений находится в таблице системного каталога pg_available_extension_versions. Строки файла SQL, начинающиеся на \echo, механизм расширений считает комментариями. Для предотвращения случайного запуска файла из psql обычно в начало файла SQL добавляют вот такую строку с предупреждением и завершают ее командой \quit:

\echo Use "CREATE EXTENSION имя" to load this file. \quit

В файле SQL можно использовать кириллицу, предварительно указав кодировку символов в параметре encoding управляющего файла. Например, можно задать русскоязычный комментарий к расширению в команде COMMENT ON EXTENSION.

Расширение как объект базы данных не принадлежит ни одной схеме. Но все объекты расширения создаются в какой-то схеме. При необходимости в SQL-файле расширения можно создавать новые схемы. Хотя это и не обязательно, но обычно все объекты расширения размещают в одной схеме. Схему для размещения объектов можно явно указать в команде CREATE EXTENSION или задать в параметре schema управляющего файла. Иначе будет использоваться первая схема из параметра конфигурации search_path. Выбранная схема явно устанавливается в search_path в начале выполнения файла SQL. Внутри файла можно обращаться к этой схеме, используя макроподстановку @extschema@. Если параметр расширения relocatable установить в true (по умолчанию false), то объекты расширения можно будет переносить в другую схему командой:

ALTER EXTENSION имя SET SCHEMA новая_схема;

Если со временем требуется изменить существующие объекты расширения или добавить новые, то выпускается новая версия. В управляющем файле новой версии расширения обычно меняется параметр default_version. А при установке возможны две ситуации:

  1. Предыдущая версия расширения не была установлена. Поэтому можно подготовить файл SQL для новой версии, включающий создание всех объектов расширения.

  2. Для тех, у кого установлена предыдущая версия расширения, следует подготовить файл SQL для обновления версии. Формат имени файла обновления следующий:

    старая_версия--новая_версия.sql
    

Внутри такого файла должны быть только команды, обновляющие объекты расширения со старой версии на новую. Само обновление выполняется командой:

ALTER EXTENSION имя UPDATE;

Перенести данные:

Утилита pg_dump обрабатывает расширения особым образом. Чтобы не потерять зависимости между объектами, нельзя просто выгружать команды определения объектов расширения (CREATE FUNCTION, CREATE VIEW, CREATE TABLE,…). Поэтому в копию, выгруженную pg_damp'ом, включается команда CREATE EXTENSION IF NOT EXISTS имя WITH SCHEMA схема; При восстановлении из такой копии расширение будет заново создано со всеми объектами и связями. Перед восстановлением нужно убедиться, что в системе установлена такая же версия расширения, что и при создании копии.

А вот данные таблиц, которые были внесены пользователями уже после создания, при переносе будут потеряны!

По умолчанию строки таблиц, вставленные после установки расширения, не будут выгружаться утилитой pg_dump. Если же требуется включить содержимое таблиц в выгрузку pg_dump, то в файле SQL расширения нужно вызвать для каждой таблицы функцию pg_extension_config_dump()

CREATE TABLE tab ...
SELECT pg_extension_config_dump('tab'::regclass);

Функция имеет два параметра. Первый — это OID таблицы, второй (необязательный) — WHERE. Эту функцию pg_dump будет применять к таблице при выгрузке. Она же используется и для последовательностей, которые могут быть связаны с таблицей. В вывод pg_dump будет записываться вызов функции setval, устанавливающий последнее полученное из последовательности значение. Функцию pg_extension_config_dump() можно вызывать только из файлов SQL-расширения!

Давайте посмотрим, где лежат файлы расширений, идущих, так сказать, в комплекте:

ls -l $(pg_config --sharedir)/extension/
total 1096
-rw-r--r-- 1 root root   274 Nov 12 11:13 adminpack--1.0--1.1.sql
-rw-r--r-- 1 root root  1535 Nov 12 11:13 adminpack--1.0.sql
-rw-r--r-- 1 root root   176 Nov 12 11:13 adminpack.control
-rw-r--r-- 1 root root   704 Nov 12 11:13 amcheck--1.0.sql
-rw-r--r-- 1 root root   154 Nov 12 11:13 amcheck.control

...

А какие расширения уже установлены?

postgres=# \dx
                 List of installed extensions
  Name   | Version |   Schema   |         Description
---------+---------+------------+------------------------------
 plpgsql | 1.0     | pg_catalog | PL/pgSQL procedural language
(1 row)

Давайте установим что-нибудь простенькое из списка выше:

postgres=# CREATE EXTENSION pg_trgm;
CREATE EXTENSION
postgres=# \dx
                                    List of installed extensions
  Name   | Version |   Schema   |                            Description
---------+---------+------------+-------------------------------------------------------------------
 pg_trgm | 1.3     | public     | text similarity measurement and index searching based on trigrams
 plpgsql | 1.0     | pg_catalog | PL/pgSQL procedural language
(2 rows)

А если подробнее?

postgres=# \dx+ pg_trgm;
                                  Objects in extension "pg_trgm"
                                        Object description
--------------------------------------------------------------------------------------------------
 function gin_extract_query_trgm(text,internal,smallint,internal,internal,internal,internal)
 function gin_extract_value_trgm(text,internal)
 function gin_trgm_consistent(internal,smallint,text,integer,internal,internal,internal,internal)
 function gin_trgm_triconsistent(internal,smallint,text,integer,internal,internal,internal)
 function gtrgm_compress(internal)
 function gtrgm_consistent(internal,text,smallint,oid,internal)
 function gtrgm_decompress(internal)
 function gtrgm_distance(internal,text,smallint,oid,internal)
 function gtrgm_in(cstring)
 function gtrgm_out(gtrgm)
 function gtrgm_penalty(internal,internal,internal)
 function gtrgm_picksplit(internal,internal)
 function gtrgm_same(gtrgm,gtrgm,internal)
 function gtrgm_union(internal,internal)
 function set_limit(real)
 function show_limit()
 function show_trgm(text)
 function similarity(text,text)
 function similarity_dist(text,text)
 function similarity_op(text,text)
 function word_similarity(text,text)
 function word_similarity_commutator_op(text,text)
 function word_similarity_dist_commutator_op(text,text)
 function word_similarity_dist_op(text,text)
 function word_similarity_op(text,text)
 operator %(text,text)
 operator %>(text,text)
 operator <%(text,text)
 operator <->(text,text)
 operator <->>(text,text)
 operator <<->(text,text)
 operator class gin_trgm_ops for access method gin
 operator class gist_trgm_ops for access method gist
 operator family gin_trgm_ops for access method gin
 operator family gist_trgm_ops for access method gist
 type gtrgm
(36 rows)

Полезные ссылки:

Правила выполнения задания:

  1. Время создания окружения занимает до 5 минут.
  2. После нажатия кнопки «Начать выполнение» для вас будет создано окружение для выполнения задания, состоящее из одной или более виртуальнах машин с Ubuntu Linux. К ним будут выданы IP, логин и пароль для доступа по SSH, а также при необходимости — дополнительных ресурсов.
  3. Также, если необходимо, вам могут быть выданы переменные, которые в задании указаны в фигурных скобках, — их надо будет подставить при выполнении задания (например, ${base_domain}).
  4. После выполнения всех пунктов задания нажмите кнопку «Проверить выполнение», и в течение 3-5 минут скрипт проверит выполнение всех условий и выставит вам оценку.
  5. В случае, если вы что-то забыли, можно исправить ошибку и отправить на проверку повторно (нажав кнопку «Проверить выполнение»).
  6. После получения удовлетворительной оценки нажмите кнопку «Завершить задание», чтобы созданное окружение уничтожилось и вы могли приступить к следующему заданию.
  7. Если у вас закончилось время (истек таймер) — окружение будет автоматически уничтожено и вам придется начать выполнение заново.
  8. Также, если вы успешно сдали задание, но у вас остались вопросы — вы всегда сможете задать их куратору после проверки (используя кнопку «Задать вопрос куратору») или в чате практикума в любое удобное для вас время. Обращаем внимание — кураторы проверяют вопросы в течение 24 часов.

Задание:

  1. На сервер Postgresql-Ubuntu18 из официальных репозиториев Ubuntu установите СУБД Postgresql версии 12.
  2. Добавьте в PostgreSQL пользователя root c правами SUPERUSER.
  3. Создайте БД rebrain и пользователя с именем extuser.
  4. Установите расширение pg_cron для Postgresql-12 c помощью пакетного менеджера apt.
  5. Настройте очистку (VACUUM) ежедневно в 2 часа ночи для БД rebrain с запуском от имени пользователя extuser.
  6. Если уверены, что все сделали правильно, сдавайте задание на проверку.

Связаться с нами