Как найти скрытые правила при миграции PL/SQL
Миграция PL/SQL требует учесть пакеты, триггеры, состояние сессии и побочные эффекты, а затем доказать эквивалентность до переноса каждого правила.

Опасность при миграции PL/SQL заключается не в преобразовании синтаксиса. Нужно выяснить, от какого поведения базы данных зависит компания, прежде чем старая база перестанет его обеспечивать. Тела пакетов, триггеры уровня строки и оператора, запланированные вызовы, состояние сессии и ветки обработки ошибок могут содержать правила, которых нет ни в одном репозитории приложения.
При нормальной миграции схему Oracle рассматривают как исполняемую систему, а не как хранилище процедур. Инвентаризация показывает, что существует. Трассировка показывает, что выполняется. Характеризационные тесты показывают, что это поведение означает. Только после этого команда может решить, где должно находиться правило: в сервисе на Go, вычислительном модуле на Rust, клиенте на TypeScript, ограничении Postgres или нигде.
Рассматривайте схему как исполняемую систему
Начните с воспроизводимой выгрузки из базы, которая по устройству совпадает с рабочей. Состояние репозитория редко полностью соответствует тому, что исполняет Oracle. Срочные исправления компилируют с рабочего компьютера, версионные объекты скрываются за синонимами, а права определяют, к каким таблицам может обращаться программный текст с правами владельца. Выгрузите DDL, исходный текст, статусы, метаданные триггеров, задания, синонимы, права и зависимости в снимок с отметкой времени.
Представление Oracle ALL_SOURCE содержит исходный текст доступных процедур, функций, пакетов, тел пакетов, триггеров, типов и тел типов. Используйте DBA_SOURCE, если у учетной записи для обследования есть необходимые права, а область работ охватывает несколько схем. Следующий запрос создает стабильный реестр исходного текста вместо каталога безымянных файлов:
SELECT owner,
type,
name,
COUNT(*) AS source_lines
FROM dba_source
WHERE owner IN ('BILLING', 'ORDERS', 'FINANCE')
GROUP BY owner, type, name
ORDER BY owner, type, name;
В результате будет одна строка на каждый хранимый объект с полями OWNER, TYPE, NAME и SOURCE_LINES. Пакет отображается двумя строками: PACKAGE и PACKAGE BODY. Не объединяйте их. Спецификация задает открытый контракт, а тело содержит закрытые процедуры, инициализацию и основную часть реализации.
Вместе с исходным текстом выгрузите DDL создания объектов. DBMS_METADATA.GET_DDL сохраняет детали объекта, которые теряются при объединении строк ALL_SOURCE.TEXT. Для пакета запросите PACKAGE_SPEC и PACKAGE_BODY, для триггера запросите TRIGGER. Рядом с каждым файлом запишите версию базы, схему, статус объекта, редакцию и время выгрузки. Команда должна уметь ответить, какая скомпилированная версия дала зафиксированный результат.
Не отфильтровывайте недействительные объекты и ошибки компиляции. Недействительный триггер все равно может заблокировать запустивший его оператор. Пакет, который стал недействительным после изменения таблицы, может перекомпилироваться при обращении в условиях, которых репозиторий никогда не воспроизводил. DBA_OBJECTS.STATUS и DBA_ERRORS превращают эти условия в проверяемые факты. Включите в реестр материализованные представления, виртуальные столбцы, индексы на основе функций, политики точного управления доступом и выражения по умолчанию, вызывающие функции. Не все они содержат PL/SQL, но каждый может вызывать хранимую логику или зависеть от нее.
Сделайте второй снимок после периода наблюдения. Сравнение часто обнаруживает средства развертывания, ночные задания или действия администраторов, которые заменяют тела пакетов вне основного процесса выпуска. Не начинайте переписывать подвижную цель. Сначала заморозьте такие изменения либо включите их в выгрузку и тестовый процесс.
Количество объектов не показывает риск. Триггер из шести строк, незаметно меняющий отчетный период, может быть важнее пакета отчетности на 9 000 строк. Инвентаризация очерчивает область поиска и обнаруживает расхождения, но не показывает, где находится значимое для бизнеса поведение.
Сначала найдите точки входа
Определите, кто может вызывать PL/SQL и какие события базы запускают его, а затем двигайтесь от этих точек внутрь. Чтение пакетов по алфавиту отнимает время: закрытые вспомогательные процедуры и мертвый программный текст выглядят такими же важными, как пути, по которым проходит каждый заказ.
Составьте таблицу точек входа как минимум из следующих источников:
- Вызовы из приложения с анонимными блоками,
CALLили полными именами процедур пакета - Активные DML-, DDL-, logon-, startup- и instead-of-триггеры
- Задания планировщика и записи в старых очередях заданий
- Представления и функции, вызываемые из операторов SQL
- Внешние инструменты, отчеты, загрузчики файлов и эксплуатационные скрипты
Для триггеров сохраняйте не одно тело. Запросите из DBA_TRIGGERS поля TRIGGERING_EVENT, TRIGGER_TYPE, TABLE_OWNER, TABLE_NAME, STATUS, WHEN_CLAUSE и ACTION_TYPE. Сопоставьте этот реестр с таблицами, в которые пишет каждый рабочий процесс приложения. Правило на таблице ORDERS может сработать при обновлении из служебного скрипта, даже если основной сервис никогда не вызывает триггер по имени.
В руководстве Oracle по триггерам PL/SQL есть два положения, которые влияют на миграцию. Триггер автоматически срабатывает для заданного события независимо от того, какой пользователь или приложение отправил оператор. Программный текст не должен зависеть от порядка, в котором оператор SQL обрабатывает строки. Если существующая система нарушает второе положение через глобальную переменную пакета, которую меняет строчный триггер, ее поведение уже может быть недетерминированным. Для проверки эквивалентности сохраните наблюдаемые результаты, но отметьте зависимость как требующую явной переработки. Не утверждайте ее в качестве требования.
Еще одна часто пропускаемая точка входа находится в инициализации пакета. Oracle выполняет раздел инициализации тела, когда сессия впервые обращается к пакету. Если там загружается конфигурация, вычисляется рабочая дата или задается переменная пакета, у первого вызова открытой процедуры есть скрытая вступительная часть. Найдите заключительный участок BEGIN ... END в каждом теле и запишите все чтения, изменения, исключения и зависимости от контекста.
В конце этого этапа должен появиться граф вызовов, корнями которого служат рабочие события, а не имена объектов. Для каждого корня укажите инициатора, транзакцию, форму входных данных, достигнутый пакет или триггер, прочитанные и измененные таблицы, внешние эффекты и наблюдаемые ошибки. Пустые поля полезны: они точно показывают, где пока не хватает фактов из работающей системы.
Для перегруженных процедур пакета нужны сигнатуры, а не только имена. Получите из ALL_ARGUMENTS позицию, режим и тип каждого аргумента, наличие значения по умолчанию и идентификатор перегрузки, затем сопоставьте сигнатуры с вызывающей стороной. Драйверы могут связывать аргументы по позиции, открывать типы коллекций Oracle или зависеть от формы курсора OUT. Замена ORDER_API.SUBMIT на конечную точку HTTP меняет контракт обмена, даже если бизнес-результат остается прежним. Учитывайте эту работу по совместимости отдельно от восстановления правил.
Статические зависимости показывают не всю программу
Считайте ALL_DEPENDENCIES полезной нижней границей. Oracle не может записать обычную зависимость времени компиляции для имени объекта, которое собирается внутри динамического SQL. Синонимы, ссылки на другие базы, разрешение имен с правами вызывающего пользователя, контексты приложения и строки из таблиц увеличивают пробелы.
Начните со статического графа:
SELECT owner,
name,
type,
referenced_owner,
referenced_name,
referenced_type
FROM dba_dependencies
WHERE owner IN ('BILLING', 'ORDERS', 'FINANCE')
ORDER BY owner, name, referenced_owner, referenced_name;
Затем найдите в исходном тексте поведение, которое граф не может надежно разрешить: EXECUTE IMMEDIATE, DBMS_SQL, OPEN ... FOR, маркеры ссылок на базы, SYS_CONTEXT, прагмы автономных транзакций, пакеты для файлов и очередей, отправку почты и обработчики исключений с записью. Если приложение выбирает вызываемую процедуру по метаданным, ищите настроенные имена процедур и в данных таблиц.
Для динамического SQL нужно проследить происхождение строки. Для каждого оператора определите шаблон, все подставляемые идентификаторы, связанные значения, схему для разрешения имен и примеры, зафиксированные во время работы. Строка EXECUTE IMMEDIATE l_sql USING p_id говорит мало, пока не ясно, обновляет ли l_sql известный раздел или вызывает отдельный пакет арендатора, выбранный из таблицы конфигурации.
В тот же анализ входит работа прав. Пакет без явного AUTHID CURRENT_USER по умолчанию использует права владельца. Его неквалифицированные ссылки на объекты и разрешения работают не так, как запрос сервиса под учетной записью конечного пользователя. Запишите AUTHID, прямые разрешения, роли, синонимы и чтение контекста приложения. При переносе процедуры в сервис можно случайно убрать оправданную границу полномочий либо дать учетной записи сервиса намного больше доступа, чем имел пакет.
Не пытайтесь инструментировать каждую строку. Добавьте наблюдение на границах: вход и выход из пакета, итог транзакции, срабатывание триггера, форма динамического оператора и внешние вызовы. Используйте идентификатор корреляции, который проходит от запроса приложения до метаданных сессии базы. Фиксируйте связанные значения только там, где это разрешает политика, и удаляйте конфиденциальные поля до сохранения. Нужна карта поведения, а не вторая рабочая база с секретными данными.
Статический анализ также преувеличивает некоторые зависимости. Тело пакета может содержать заброшенные процедуры со ссылками на таблицы, которыми никто не пользовался много лет. Если объявить каждое ребро активным, область миграции будет расти быстрее доказательств. Ведите отдельные графы «может вызвать» и «вызывал», а со вторым храните период наблюдения и нагрузку. Отсутствие в трассировке не доказывает, что программный текст мертв, но позволяет потребовать владельца или специальный тест до его восстановления.
Запишите найденное в реестр поведения
Реестр поведения превращает находки в исходном тексте в проверяемые контракты. Одна строка описывает одно значимое снаружи правило: входные и выходные данные, изменения состояния, ошибки и подтверждающие факты. Без такого промежуточного документа архитекторы склонны целиком назначать пакеты целевым компонентам и переносить случайные границы в новую систему.
Рассмотрим процедуру пакета, которая подтверждает счет. Она проверяет статус, вычисляет налог по таблицам клиентов и дат действия, добавляет бухгалтерские проводки, меняет состояние счета и ставит уведомление в очередь. Это не одно правило. В реестре нужно разделить допустимость операции, выбор налога, проводку, переход состояния и намерение отправить уведомление. У каждого из них может быть свой целевой компонент и свой способ проверки.
Полезная запись в реестре содержит:
- Идентификатор правила и понятное описание с местом в исходном тексте
- Событие запуска и необходимое состояние сессии, таблиц и пакета
- Входы, выходы, изменения, сообщения, файлы, фиксации и откаты
- Граничные случаи, ошибки Oracle, собственные коды ошибок и правила повторения
- Факты из исходного текста, трассировок, рабочих примеров и подтверждение владельца
Присвойте каждому правилу статус: наблюдаемое, выведенное, спорное, утвержденное или устаревшее. Один исходный текст подтверждает статус «выведенное», если ветка может быть недостижима. Зафиксированное выполнение подтверждает «наблюдаемое». Финансовый или эксплуатационный отдел может утвердить, считается ли странное поведение частью контракта. Это предотвращает обычное совещание, на котором неожиданный результат называют ошибкой лишь потому, что новая система его не повторила.
Отделяйте бизнес-правила от механики базы. «Счет нельзя провести в закрытом периоде» является правилом. «Триггер BEFORE INSERT читает PERIOD_CONTROL и выдает -20041» является реализацией. «Установить UPDATED_AT из SYSTIMESTAMP» может быть политикой хранения. «Увеличить глобальную переменную пакета» может быть обходным решением. Следствие простое: переносите правило, тестируйте старый механизм и сохраняйте его лишь тогда, когда его семантика входит в контракт.
Записывайте и отсутствие действий. Если прямые обновления SQL обходят проверку приложения, но все равно попадают в триггер, фактическую границу контроля задает триггер. Если пакет сам выполняет commit, вызывающая сторона не может откатить всю операцию, хотя по программному тексту кажется владельцем транзакции. Эти неудобные факты определяют переключение. Не смягчайте их в архитектурном описании.
По возможности превращайте разногласия в исполняемые примеры. Если эксплуатационный отдел разрешает отмену задним числом, а финансовый запрещает, сохраните оба варианта, ожидаемые результаты и условия данных. Попросите владельца утвердить один результат в реестре. Текстовое требование «правильно обрабатывать задние даты» пройдет все проверки, но не даст разработчикам результата для сравнения.
Реестр также управляет удалением. Если для процедуры никто не может указать вызывающего участника, наблюдаемое выполнение, регуляторную причину или утвержденный пример, пометьте ее кандидатом на удаление. Сохраните старый исходный текст и докажите, что вызовов нет. Не тратьте время на перенос лишь потому, что процедура компилируется.
Тестируйте транзакции, а не отдельные функции
Характеризационные тесты должны обращаться к старой системе через настоящие открытые границы и сравнивать полный результат транзакции. Модульный тест закрытой функции расчета налога не увидит эффекты триггеров, состояние пакета, настройки NLS, расход номеров последовательности, преобразование исключений и фиксацию.
Создайте временную среду Oracle из маскированного набора данных с сохраненной ссылочной целостностью. Явно задайте входные параметры сессии: часовой пояс, NLS_DATE_FORMAT, числовые разделители, текущую схему, контекст приложения и источники рабочей даты. Если важны точные идентификаторы, перед каждым сценарием возвращайте таблицы и последовательности в известное состояние. Для тестов состояния пакета используйте отдельные сессии.
Oracle указывает, что каждая сессия получает собственный экземпляр пакета, а значения пакета с состоянием обычно живут до конца сессии. Перекомпиляция уже созданного экземпляра может удалить состояние и вызвать ORA-04068 при следующем обращении. Поэтому пул соединений превращает глобальные переменные пакета в скрытую память каждого соединения. Нужны сценарии для новой сессии, повторных вызовов в одной сессии, двух одновременных сессий, повторного использования сессии из пула, отката и признания пакета недействительным, если рабочие развертывания способны это вызвать.
Для каждого теста сохраняйте нормализованную запись наблюдения:
{
"case": "closed-period-credit",
"entry": "billing.invoice_api.post_credit",
"result": {"status": "error", "oracle_code": -20041},
"tables": {"invoice": [], "ledger_entry": []},
"events": [],
"transaction": "rolled_back"
}
Новая реализация должна выдавать такое же наблюдаемое бизнес-поведение, но стек Oracle или значение последовательности могут отличаться. Заменяйте созданные идентификаторы стабильными псевдонимами, сравнивайте деньги в заявленном масштабе, упорядочивайте множества только при договорном порядке и сравнивайте время с точностью старого интерфейса. Сохраняйте точные собственные коды ошибок, если от них зависят ветки вызывающей стороны. В остальных случаях сопоставьте их с явной ошибкой предметной области на границе совместимости и протестируйте это сопоставление.
Намеренно проверяйте сбои и частично выполненную работу. Вызовите ошибку повторяющегося ключа после записи аудита. Сделайте очередь уведомлений недоступной. Выдайте исключение из строчного триггера после обработки нескольких строк. Проверьте массовый DML, где время срабатывания триггеров оператора и строки меняет сохраняющийся результат. Успешный вызов процедуры не обнаружит автономную транзакцию, которая сохранила строку аудита после отката бизнес-транзакции.
Распространенный сбой выглядит так. Приложение начинает транзакцию, вызывает пакет для резервирования кредита, добавляет заказ и откатывает транзакцию после ошибки распределения запасов. Пакет обновляет глобальный кеш «доступного кредита», а автономная процедура аудита фиксирует запись о резерве. Обновление таблицы откатывается, но значение пакета остается в сессии пула, а запись аудита остается зафиксированной. Замена, в которой все входит в одну чистую транзакцию сервиса, при следующем запросе поведет себя иначе. В реестре нужно решить, считать ли эти остатки требованиями, допустимыми дефектами или поведением для удаления. Тесты должны закрепить утвержденный вариант.
Для порядка триггеров нужны отдельные сценарии, если несколько триггеров относятся к одной таблице и одному моменту. Oracle предоставляет FOLLOWS и в ограниченных случаях PRECEDES для объявленных связей, но несвязанные триггеры не получают надежного полного порядка. Сохраните DDL и тестируйте конечный результат операторов над несколькими строками. Не требуйте в целевой системе случайной последовательности срабатывания, если она не объявлена в источнике и от нее не зависит результат для бизнеса.
Измеряйте покрытие по правилам реестра и точкам входа, а не по строкам PL/SQL. Тест может выполнить каждую строку налогового пакета, но не доказать, какая ставка действует на границе периода. И наоборот, компактная матрица дат, юрисдикций, классов клиентов и состояний отмены способна описать контракт, не заходя в защитные ветки. Обычное покрытие программного текста оставьте диагностикой, а не условием приемки.
Рабочий трафик дает примеры, а не истину
Записанный рабочий трафик лучше всего дает реалистичные входные данные, но не определяет всю спецификацию. В нем слишком много обычных случаев, есть исторические случайности и почти нет входов, которые должны завершаться ошибкой.
Записывайте запросы на границе, где еще виден смысл входных данных. Включайте вызванную операцию, порядок вызовов в транзакции, очищенные параметры, значимый контекст сессии, класс результата и идентификаторы для сбора затронутых строк. Для точек входа через SQL записывайте связанные значения и объединение в транзакции, а не только текст SQL. Для пакетной обработки сохраняйте форму файла и контрольные итоги, но не копируйте ограниченные данные в неуправляемое тестовое хранилище.
Воспроизводите каждый сценарий в старой и новой реализации из эквивалентного начального состояния. Сравнивайте возвращаемые значения, ошибки, изменения базы, отправленные события и границы фиксации. При расхождении классифицируйте причину до изменения программы: отсутствующее правило, намеренная переработка, недетерминированность, плохие тестовые данные или старый дефект, который владелец решил удалить.
Дополняйте трафик сценариями из реестра. Добавьте граничные даты, null, повторные запросы, повторы после тайм-аута, максимальный поддерживаемый масштаб чисел, пользователей без прав, закрытые отчетные периоды и одновременные обновления одной сущности. Добавьте метаморфные проверки там, где точный результат трудно перечислить. Например, проведение и последующая отмена допустимого счета должны свести его чистое влияние на бухгалтерскую книгу к нулю с учетом старого правила округления.
Отбирайте примеры по поведению, а не только по объему. Миллион успешных заказов добавит мало подтверждений, когда формы входа повторяются. Одно закрытие года, переход на летнее время или ручная корректировка могут покрыть уникальную ветку. Намеренно сохраняйте редкие случаи и создавайте для них стабильные данные. Частота в рабочей системе должна направлять тесты производительности, а последствия для бизнеса и уникальность ветки должны определять покрытие эквивалентности.
При переписывании систем, включая базы PL/SQL, CodeHero проверяет эквивалентность по записанному рабочему трафику и читает языки вокруг базы как единый исходный текст. Это важно, потому что контракт хранимой процедуры часто частично находится в вызывающем Java-коде, скрипте планировщика и строках, которые изменяет триггер. При этом нужны отрицательные и граничные случаи из реестра: большой объем воспроизведения не докажет поведение, которое ни разу не встретилось в трафике.
Не передавайте записанные рабочие данные модели или тестовой среде без решения об их классификации. Маскирование должно сохранять свойства, которые используют правила: группы равных значений, порядок дат, префиксы счетов и ссылочную целостность. Замена всех значений случайным текстом может скрыть личность и одновременно уничтожить именно те случаи, которые должна проверить миграция.
Разместите правило на самой узкой надежной границе
Размещайте правило там, через что проходит каждое значимое изменение и где команда может его наблюдать и тестировать. Обычно получается разделенная архитектура, а не перенос всего PL/SQL в сервисы или сохранение всех правил в Postgres.
Используйте ограничения базы для инвариантов, которые можно выразить относительно строки или реляционного состояния: допустимость null, уникальность, внешние ключи и проверяемые диапазоны. Ограничения охватывают всех авторов изменений и дают планировщику запросов полезные сведения. Не заменяйте декларативное ограничение проверкой в приложении только потому, что ее проще версионировать.
Оставляйте небольшую функцию или триггер в базе только тогда, когда правило действительно относится ко всем авторам записи, не выражается декларативно, а эти авторы продолжат обходить единый сервис. Сделайте эффекты явными и минимальными. Триггер, который записывает контекст аудита, может быть оправдан. Триггер, который рассчитывает цену, меняет пять таблиц, отправляет сообщение и автономно делает commit, скрывает рабочий процесс, которому нужен API с определенным владельцем.
Помещайте правила процесса в сервис, когда они координируют агрегаты, вызывают внешние системы, требуют явных повторов или наблюдаемости на уровне продукта. Сервис должен владеть транзакцией либо использовать outbox для работы после фиксации. Не публикуйте сообщение до commit в надежде, что потребители переживут откат. Не позволяйте одновременно отправлять его триггеру совместимости и новому сервису.
Переносите вычислительные ядра в Rust только тогда, когда работе помогает узкая и независимо тестируемая граница расчета. Правила представления помещайте в клиент на TypeScript только тогда, когда сервер или база по-прежнему обеспечивают исходный инвариант. Отключенная кнопка дает полезную подсказку, но не является авторизацией.
Postgres не становится Oracle после замены синтаксиса. У состояния сессии пакета нет прямого аналога, пустые строки и null различаются, исключения и автономные транзакции работают иначе, а порядок триггеров требует явного проектирования. Переработайте эти границы вместо дословного переноса. Явный запрос сервиса, транзакция и запись outbox понятнее, чем заново созданная сеть скрытых обратных вызовов.
В решении по каждому правилу реестра укажите выбранного владельца, точку контроля, план совместимости, тестовые случаи и условие удаления реализации Oracle. Если у правила нет владельца, оно не перенесено. Если его обеспечивают два компонента, запишите, какой из них главный и как долго продлится дублирование.
Не запускайте правила дважды при переключении
Самый большой риск переключения связан с повторным выполнением: новый сервис применяет правило, пока старый триггер незаметно применяет его еще раз. Возникают двойные бухгалтерские проводки, повторные уведомления, несовпадающие отметки времени или обновление, которое проходит одну проверку и не проходит другую.
Создайте матрицу активации по каждому правилу. Строками будут идентификаторы из реестра, столбцами будут старое приложение, пакет Oracle, триггер Oracle, новый сервис, ограничение или триггер Postgres и потребитель событий. Для каждого состояния развертывания отметьте одного главного исполнителя и наблюдателей. Не допускайте состояния с двумя исполнителями, если операция не доказана как идемпотентная, а дублирование не введено намеренно.
Теневое выполнение не должно менять общее рабочее состояние. Запустите новую логику решений в режиме наблюдения либо воспроизведите записанные входы в изолированной целевой системе, затем сравните предложенный результат с зафиксированным результатом Oracle. Для процессов с внешними эффектами подставьте приемник, который записывает намерение, но не отправляет почту, не списывает деньги и не публикует в рабочую тему.
Двойная запись популярна, потому что кажется удобной для отката. Обычно она создает два вида отказа и неоднозначный источник истины. Предпочтительнее один автор записи с захватом изменений или outbox, измеренной задержкой репликации и запросом сверки. Если временной двойной записи не избежать, назначьте ключ идемпотентности на исходной границе запроса и сохраните результат с обеих сторон.
Переключайте целостную точку входа, а не произвольный файл пакета. Переносите процедуру, зависимые триггеры, транзакционную семантику и последующие эффекты как один срез поведения. Блокируйте или перенаправляйте прямых авторов записи, способных обойти новый центр полномочий. Оставляйте фасад совместимости только тогда, когда вызывающей стороне нужно время. Пусть фасад вызывает нового владельца, а не содержит вторую реализацию.
План отката должен определять направление данных, а не только направление развертывания. Укажите, какая система остается главной, какие записи приостанавливаются, как существующие только в целевой системе записи при необходимости вернутся в Oracle и как будут сверены уже отправленные эффекты. Откат контейнера не отменяет бизнес-операцию после выхода денег, сообщений или файлов за границу транзакции.
Отключение Oracle служит приемочным тестом
Миграция PL/SQL закончена, когда бизнес может работать с отключенным соответствующим поведением Oracle, а команда способна доказать правильность результатов. Фраза «все тела пакетов перенесены» ничего не говорит о триггерах, заданиях, глобальных переменных сессии, эксплуатационных скриптах и вызывающих системах, которые все еще подключаются напрямую.
Для каждой точки входа требуйте замкнутую цепочку от инициатора до утвержденного правила реестра, владельца в целевой системе, пройденных характеризационных сценариев, состояния переключения и наблюдения в рабочей среде. Повторите инвентаризацию схемы и сравните с исходным снимком. Для каждого оставшегося активного триггера, права выполнения, задания планировщика, синонима и подключения приложения нужна явная причина.
Затем проведите тест с запретом в среде, подобной рабочей. Отзовите право на старый путь выполнения или отключите перенесенный триггер, запустите весь набор трафика и специально созданных сценариев, следите за попытками подключения. Тест должен завершиться ошибкой, если хотя бы один путь еще зависит от Oracle. Успешный запуск дает более сильное подтверждение, чем таблица, в которой каждый владелец компонента отметил строку выполненной.
Храните снимок исходного текста, реестр поведения, нормализованные наблюдения, решения и результаты проверки эквивалентности как единый набор фактов. Они объясняют не одно устройство старой программы. Они показывают, какие странности бизнес принял, какие дефекты решил убрать и где теперь находится каждое оставшееся правило.
CodeHero выполняет переписывание унаследованных систем менее чем за 30 дней, но скорость не оправдывает догадки о поведении базы. Быстро двигаться позволяет одновременное обследование всей системы, превращение находок в исполняемые сравнения и отказ считать правило перенесенным, пока его еще должен обеспечивать Oracle.
Вопросы
Как найти весь PL/SQL в базе данных Oracle?
Запросите из DBA_SOURCE или ALL_SOURCE пакеты, тела пакетов, процедуры, функции, триггеры и типы, затем извлеките их DDL через DBMS_METADATA. Добавьте задания, права, синонимы, недействительные объекты, виртуальные столбцы, индексы на основе функций и политики, потому что исходный текст не описывает все пути вызова.
Находит ли ALL_DEPENDENCIES все зависимости PL/SQL?
Нет. Представление записывает обычные зависимости времени компиляции, но динамический SQL, настраиваемые имена, синонимы, ссылки на базы, разрешение с правами вызывающего пользователя и внешние вызовы могут не попасть в граф. Дополните его поиском по исходному тексту и трассировками выполнения.
Следует ли переносить бизнес-логику из триггеров базы?
Перенесите рабочие процессы и внешние эффекты в сервис с определенным владельцем, но оставьте общие инварианты на самой узкой границе, которую пересекают все авторы записи. Декларативное ограничение базы обычно лучше триггера или повторяющихся проверок приложения.
Как протестировать пакет PL/SQL перед переносом?
Вызывайте его открытые точки входа на контролируемом наборе Oracle и сохраняйте возвращаемые значения, ошибки, изменения таблиц, события и итоги транзакций. Для пакета с состоянием повторите сценарии в новых, повторно используемых, одновременных и ставших недействительными сессиях.
Почему состояние пакета Oracle важно при миграции?
Переменные пакета могут жить до конца сессии базы, поэтому пул соединений переносит скрытое состояние между запросами. Замена без состояния способна изменить поведение, если тесты не обнаружат зависимость, а владельцы не решат, сохранять ее или удалять.
Достаточно ли рабочего трафика для доказательства эквивалентности PL/SQL?
Нет. Воспроизведение дает реалистичные входы, но пропускает редкие сбои, граничные даты, вызовы без прав и неиспользуемые ветки. Добавьте сценарии из реестра поведения и сравнивайте полные последствия транзакции.
Как переносить автономные транзакции?
Сначала выясните, зачем старый программный текст независимо фиксирует работу и зависит ли бизнес от ее сохранения после отката. Во многих случаях аудит или сообщения становятся понятнее как явный outbox либо отдельная запись со своим владельцем, но решение должно исходить из утвержденного поведения.
Можно ли напрямую перевести Oracle PL/SQL в PostgreSQL?
Синтаксис преобразовать можно, но прямой перенос пропускает различия в состоянии пакетов, пустых строках и null, ошибках, правах, транзакциях и триггерах. Сначала восстановите поведение, затем выберите естественного владельца для каждого правила.
Как избежать двойных эффектов триггеров при переключении?
Ведите матрицу активации с одним главным исполнителем для каждого правила реестра. Запускайте новую логику в теневом режиме без общих изменений, а когда новый путь начнет писать, отключите или обойдите старого исполнителя.
Когда миграция PL/SQL действительно завершена?
Она завершена, когда перенесенные пути Oracle можно отключить, а воспроизведение трафика и специальные сценарии продолжают проходить. У каждого оставшегося триггера, задания, права, синонима и прямого подключения должны быть явный владелец и причина.