LINUX.ORG.RU

Миграции в условиях паранойи - полная проверка структуры таблиц

 , , , ,


0

2

Привет, народ.

Требуется тут сделать нестандарную самописную подсистему миграции в БД PostgreSQL 9.6 с учетом параноидальности начальства.

В стандартном виде миграция осуществляется по алгоритму: где-то хранится номер последнего обновления, и если есть новое обновление, то оно применяется поверх тех данных и структуры что есть в БД. При этом все система полагается на то, что если известна версия текущей структуры, то однозначно известна и сама структура, и эта структура правильная. И поэтому миграция применяется без реальной проверки структуры таблиц. И во всех разумных сценариях это работает.

Теперь рассмотрим параноидальный сценарий:

Предполагается, что в любой момент может появиться «тайный криворукий вредитель», который что-то сделает с таблицами в БД. С самими БД он ничего не сделает (не спрашивайте почему, никто этого не знает), а вот с таблицами - сделает. Поменяет тип столбца, переименует столбец или вовсе удалит, уберет индекс или еще что-то эдакое. Или вообще удалит таблицу.

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

Вопрос 1: как автоматически «вычислять» структуру таблиц, сформировавшуюся за все миграции, чтобы иметь возможность ее проверить?

Вопрос 2: как непосредственно проверить структуру таблиц на соответствие «вычисленной» на предыдущем шаге структуре?

Есть ли готовые SQL-команды или подходы для таких действий?

Используемые инструменты: C++, Qt. Никаких этих ваших яв, питонов, пхп и сторонних библиотек быть не должно.

PS: Я не прикалываюсь, я все это спрашиваю абсолютно серьезно.

★★★★★

Приложение свалится если тип поменяет, а вот удаления индекса не заметишь, если база маленькая. Структуру можно вытянуть запросом. Там в отличии от MYSQL, где есть DESCRIBE нужно портянку писать… Можно посмотреть как в любой ORM система миграций реализована и стащить ее от туда

rtxtxtrx
()

Фига вам там заняться нечем совсем.

БД PostgreSQL 9.6

Напомню на всякий случай, что она протухла уже два года как.

Вопрос 1: как автоматически «вычислять» структуру таблиц, сформировавшуюся за все миграции, чтобы иметь возможность ее проверить?

Создаешь пустую БД, прогоняешь в ней миграции с самого начала, получаешь «эталонную структуру», с которой сравниваешь.

Вопрос 2: как непосредственно проверить структуру таблиц на соответствие «вычисленной» на предыдущем шаге структуре?

Есть куча готовых инструментов, но тебе они по условию задачи не подойдут. Выполняй запросы к системным таблицам постгреса, чтобы получить список таблиц, столбцов этих таблиц, ограничений, индексов, вьюх, функций и т.д. Сравниваешь эти списки для обоих БД. Готовых команд для тебя нет, читай доки, вики постгреса, гугли. Также у psql была опция или мета-команда, которая включает печать SQL-запросов, которые использовались при выполнении мета команды — т.е. если ты в нём запустишь, например, \d table_name, он тебе покажет также запросы, которые эта команда выполняет (какая опция, я не помню, смотри доки).

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Создаешь пустую БД, прогоняешь в ней миграции с самого начала, получаешь «эталонную структуру», с которой сравниваешь.

Можно ещё создать временную схему в текущей БД и в ней прогонять миграции, если создавать новую БД не вариант.

Есть куча готовых инструментов, но тебе они по условию задачи не подойдут

Зато можно подглядеть в исходниках, как это реализовано.

theNamelessOne ★★★★★
()

Поменяет тип столбца, переименует столбец или вовсе удалит, уберет индекс или еще что-то эдакое. Или вообще удалит таблицу.

Так запросы на модификацию структур данных не являются транзакционными, их не откатить.

Поэтому защититься от такого автоматическими средствами никак.

Как выше правильно написали - надо поднять отдельную базу, в нет прокатать миграцию и посмотреть на изменения. По-другому никак.

alex0x08 ★★★
()

Предполагается, что в любой момент может появиться «тайный криворукий вредитель»

От идиотов тебя никакие хитры миграции не спасут. Спасут бэкапы, впрочем, до какой-то степени.

БД PostgreSQL 9.6

Она там случайно не на Debian 8 крутится? Если у вас уже в этом месте проблемы с идиотами, то вами вряд ли что-то поможет

Используемые инструменты: C++, Qt.

Треш какой. Qt на сервере. Плюсы. Из которых идет работа с СУБД(видимо веб-сервер? микросервис?). Ад.

Флаг вам в руки и барабан на шею, желаю убиться об стену.

lovesan ★★
()

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

Anoxemian ★★★★★
()

И если структура неправильная, то удалять все данные, и прогонять все миграции заново с самой первой

Автоматом? Желаю удачи, чтобы твой скрипт не глюконул и не стер всю базу зря, а то кто знает, что в такой ситуации сделает твой неадекватный начальник)

goingUp ★★★★★
()
Ответ на: комментарий от alex0x08
postgres=# select * from test;
ERROR:  relation "test" does not exist
LINE 1: select * from test;
                      ^
postgres=# begin;
BEGIN
postgres=*# create table test(x integer);
CREATE TABLE
postgres=*# select * from test;
 x 
---
(0 rows)

postgres=*# rollback;
ROLLBACK
postgres=# select * from test;
ERROR:  relation "test" does not exist
LINE 1: select * from test;
vbr ★★★
()
Ответ на: комментарий от alex0x08

Что значит «придется»? Не хочешь - делай без транзакций. Но вообще это очень удобно. У тебя или миграция прошла успешно, или всё откатилось как было.

vbr ★★★
()

1. Не надо вычислять структуру, просто сделай дамп текущей, раскатай её отдельно и попробуй мигрировать. Если отпало - структура кривая. Ну или рядом раскатай структуру из миграций и сравни с текущей.

2. Не понял вопроса.

ya-betmen ★★★★★
()

Зачем вообще какая-то пустая база?

Если кратко.

Метаданные каждой из таблиц помещаете в отдельные списки (SQLite, ...), а затем делайте с ними всё что угодно (элементы списков должны содержать метаданные полей).

Лаба (по сложности реализации).

Если этот алгоритм не будет использован для других задач, то реализовать его можно на чём угодно (хотя могу быть и не прав).

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 5)
Ответ на: комментарий от alex0x08

О как, не знал что такое прикрутили.

Всю жизнь было.

И что получается всю миграцию целиком придется в одну транзакцию пихать?

Не «придётся», а «слава те господи, можно». Потому что если миграция падает, а DDL не транзакционный, то дальше – только долго и мучительно пердолиться вручную (обсуждение древнее, с тех пор наверняка пофиксили, но лично для меня ТАКИЕ факапы – диагноз навсегда). Поэтому SQL-сервер без транзакционного DDL – это говно собачье.

UPD: Из того же обсуждения.

Меня кстати архи порадовало, что у SQLite тоже транзакционный DDL. Не ожидал от крошечного embedded движка.

dimgel ★★★★★
()
Последнее исправление: dimgel (всего исправлений: 1)
Ответ на: комментарий от theNamelessOne

Создаешь пустую БД, прогоняешь в ней миграции с самого начала, получаешь «эталонную структуру», с которой сравниваешь.

Проблема в том, что среда так заранее настраивается, что из-под пользователя не создашь новую пустую БД. А состав БД заранее ограничен.

Я так понял, что невозможно создать временную БД, можно создавать только временные таблицы. А при создании «эталонной структуры» в текущей БД уже таблицы есть, и команды будут воздействовать на них.

Так вот вопрос: когда устанавливается PostgreSQL, в ней автоматически создается некая БД с именем «postgres». Вроде как она пустая. И это не «template0». Даже не знаю, зачем она создается. Так вот, можно ли БД «postgres» использовать для генерации эталонной структуры? Ни на что изменение этой БД не повлияет?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

из-под пользователя не создашь новую пустую БД

А кстати: в SQLite можно создать временную базу :memory:. Если у тебя в миграциях нет никаких постгрес-специфичных изысков (в т.ч. множества схем – в общем, маловероятно, но вдруг), то прогнать миграции для получения эталонной структуры базы можно на :memory: – и никто не догадается. :) Разве что

сторонних библиотек быть не должно

SQLite прилинковать придётся.

dimgel ★★★★★
()
Последнее исправление: dimgel (всего исправлений: 1)
Ответ на: комментарий от dimgel

Если ты создашь одинаковую таблицу в SQLite и в PostgreSQL, и получишь их структуру через sqlitedump/pg_dump, то ты увидишь что описание таблиц неплохо так разнится. Особенностей столько, что этот подход вообще не вариант.

Xintrea ★★★★★
() автор топика

Требуется тут сделать нестандарную самописную подсистему миграции

Сделай.

Я не прикалываюсь, я все это спрашиваю абсолютно серьезно.

Нормальная работа для студента.

как непосредственно проверить структуру таблиц на соответствие

Ну, либо соответствует, либо не соответствует. Путём поэлементного сравнивания.

как автоматически «вычислять» структуру таблиц

Иметь модель, к которой применять команды преобразования, чтобы получить результат.

Проблем никаких, просто достаточно много достаточно тупого кода, всё по документации.

Shushundr ★★★
()
Ответ на: комментарий от Xintrea

Нет, походу с отдельной базой, даже с существующей «postgres» не получится работать.

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

В общем, надо как-то извращаться и пользоваться только тем что есть.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Проблема в том, что среда так заранее настраивается, что из-под пользователя не создашь новую пустую БД. А состав БД заранее ограничен.

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

Так вот, можно ли БД «postgres» использовать для генерации эталонной структуры? Ни на что изменение этой БД не повлияет?

В теории можешь, она создаётся по умолчанию и никак не используется.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Можешь тогда создать временную схему в текущей БД

А проблем с пересечением названий таблиц с public схемой не должно возникнуть? Если в SQL-командах будет ourScheme.ourTable - этого достаточно?

А можно перед SQL-командой отдельной командой выбрать рабочую схему, чтобы после этой команды последующие SQL-запросы выполнялись в рамках выбранной схемы?

UPD: Ага, похоже схему можно выбрать командой:

SET search_path TO ourScheme;

UPD2: Точнее, чтобы все четко работало, схему лучше выбирать так:
SET search_path TO pg_catalog, ourScheme;

А потом перетыкаться обратно на public:
SET search_path TO pg_catalog, public;

Xintrea ★★★★★
() автор топика
Последнее исправление: Xintrea (всего исправлений: 3)

Можно посмотреть на CDC, там же посмотреть как сканировать online-log/redo файлы. В лог файлах информация об изменениях в структурах таблиц присутствует. Исходя из типа изменения либо просто изменить целевую таблицу (ALTER TABLE COLUMN TYPE) и продолжить работу дальше, либо изменить целевую таблицу (например, добавить колонку) ну и, соответственно, перезалить данные. Но работа сия есть долгая и муторная.

Либо если есть деньги - просто купить готовое решение. Например, hvr-software.com (там ребрендинг произошел)

gsvg
()