Zum Inhalt springen
14. Aug. 2026·8 Min. Lesezeit

So finden Sie versteckte Regeln bei einer PL/SQL-Migration

Eine PL/SQL-Migration gelingt, wenn Sie Packages, Trigger, Sitzungszustand und Nebenwirkungen erfassen und vor dem Umzug jeder Regel Parität belegen.

So finden Sie versteckte Regeln bei einer PL/SQL-Migration

Der gefährliche Teil einer PL/SQL-Migration ist nicht die Umwandlung der Syntax. Gefährlich ist, herauszufinden, von welchem Datenbankverhalten das Unternehmen abhängt, bevor die alte Datenbank dieses Verhalten nicht mehr liefert. Package-Bodys, Zeilen- und Statement-Trigger, geplante Aufrufe, Sitzungszustand und Fehlerpfade können Regeln enthalten, die in keinem Repository der Anwendung stehen.

Eine glaubwürdige Migration behandelt das Oracle-Schema als ausführbares System und nicht als Ablage für Stored Procedures. Die Inventur zeigt, was vorhanden ist. Tracing zeigt, was läuft. Charakterisierungstests zeigen, was es bedeutet. Erst danach kann ein Team entscheiden, ob eine Regel in einen Go-Service, einen Rust-Kernel, einen TypeScript-Client, ein Postgres-Constraint oder nirgendwohin gehört.

Das Schema als ausführbares System inventarisieren

Beginnen Sie mit einer wiederholbaren Extraktion aus einer produktionsnahen Datenbank, denn ein Quellcode-Checkout entspricht selten genau dem, was Oracle ausführt. Hotfixes werden von einem Arbeitsplatz aus kompiliert, editionierte Objekte verbergen sich hinter Synonymen, und Grants bestimmen, auf welche Tabellen Code mit Definer-Rechten zugreifen kann. Exportieren Sie DDL, Quelltext, Status, Trigger-Metadaten, Jobs, Synonyme, Grants und Abhängigkeiten in einem mit Zeitstempel versehenen Snapshot.

Oracles View ALL_SOURCE liefert den Quelltext zugänglicher Prozeduren, Funktionen, Packages, Package-Bodys, Trigger, Typen und Type-Bodys. Nutzen Sie DBA_SOURCE, wenn das Bewertungskonto die nötigen Rechte hat und mehrere Schemas umfasst werden. Die folgende Abfrage erzeugt eine stabile Quellcode-Inventur statt eines Verzeichnisses voller anonymer Dateien:

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;

Die Ausgabe enthält eine Zeile je gespeichertem Objekt: OWNER, TYPE, NAME und SOURCE_LINES. Ein Package erscheint in getrennten Zeilen als PACKAGE und PACKAGE BODY. Fassen Sie diese nicht zusammen. Die Spezifikation ist ein öffentlicher Vertrag; der Body enthält private Routinen, Initialisierungscode und die meisten Implementierungsdetails.

Extrahieren Sie neben dem Text auch die Erstellungs-DDL. DBMS_METADATA.GET_DDL erhält Details auf Objektebene, die beim Zusammenfügen von ALL_SOURCE.TEXT verloren gehen. Fordern Sie für ein Package PACKAGE_SPEC und PACKAGE_BODY an, für einen Trigger TRIGGER. Speichern Sie Datenbankversion, Schema, Objektstatus, Edition und Extraktionszeit bei jeder Datei. Ein Migrationsteam muss beantworten können, welche kompilierte Definition ein erfasstes Ergebnis erzeugt hat.

Nehmen Sie ungültige Objekte und Kompilierungsfehler auf, statt sie herauszufiltern. Ein ungültiger Trigger kann die auslösende Anweisung weiterhin blockieren, und ein Package, das durch eine Tabellenänderung ungültig wurde, kann sich bei Bedarf unter Bedingungen neu kompilieren, die das Quellcode-Repository nie abgebildet hat. DBA_OBJECTS.STATUS und DBA_ERRORS machen diese Bedingungen sichtbar. Inventarisieren Sie auch materialisierte Views, virtuelle Spalten, funktionsbasierte Indizes, Richtlinien für feingranulare Zugriffskontrolle und Default-Ausdrücke, die Funktionen aufrufen. Nicht alle sind PL/SQL-Container, doch jedes davon kann gespeicherte Logik aufrufen oder davon abhängen.

Erstellen Sie nach dem Beobachtungszeitraum einen zweiten Snapshot. Ein Diff deckt oft Deployment-Werkzeuge, nächtliche Jobs oder Administratoren auf, die Package-Bodys außerhalb des vorgesehenen Release-Prozesses ersetzen. Beginnen Sie keinen Rewrite gegen ein bewegliches Ziel, ohne diese Änderungen entweder einzufrieren oder in Extraktion und Testpipeline aufzunehmen.

Die Anzahl ist kein Risikowert. Ein sechszeiliger Trigger, der unbemerkt eine Buchungsperiode ändert, kann wichtiger sein als ein 9.000 Zeilen langes Reporting-Package. Die Inventur steckt den Suchraum ab und zeigt Drift; sie verrät nicht, welcher Code fachliche Bedeutung trägt.

Einstiegspunkte vor Package-Bodys finden

Verfolgen Sie zuerst, wer PL/SQL aufrufen kann und welche Datenbankereignisse es auslösen. Lesen Sie dann von diesen Einstiegspunkten nach innen. Packages alphabetisch durchzugehen kostet Zeit, weil private Hilfsroutinen und toter Code so wichtig aussehen wie Pfade, die bei jedem Auftrag laufen.

Erstellen Sie eine Tabelle der Einstiegspunkte mindestens aus diesen Quellen:

  • Anwendungsaufrufe mit anonymen Blöcken, CALL oder qualifizierten Package-Prozedurnamen
  • Aktivierte DML-, DDL-, Logon-, Startup- und Instead-of-Trigger
  • Scheduler-Jobs und Einträge in älteren Job-Warteschlangen
  • Views und Funktionen, die aus SQL-Anweisungen aufgerufen werden
  • Externe Werkzeuge, Berichte, Datei-Loader und Betriebsskripte

Erfassen Sie bei Triggern mehr als den Body. Fragen Sie DBA_TRIGGERS nach TRIGGERING_EVENT, TRIGGER_TYPE, TABLE_OWNER, TABLE_NAME, STATUS, WHEN_CLAUSE und ACTION_TYPE ab. Verknüpfen Sie diese Inventur mit den Tabellen, die jeder Anwendungsablauf schreibt. Eine Regel an ORDERS kann laufen, wenn ein Supportskript die Tabelle ändert, selbst wenn der Hauptservice den Trigger nie namentlich aufruft.

Oracles Leitfaden zu PL/SQL-Triggern nennt zwei Punkte, die den Migrationsentwurf beeinflussen. Trigger laufen bei ihren definierten Ereignissen automatisch, unabhängig davon, welcher Benutzer oder welche Anwendung die Anweisung absetzt. Code darf außerdem nicht von der Reihenfolge abhängen, in der eine SQL-Anweisung Zeilen verarbeitet. Verstößt das vorhandene System über eine Package-Globalvariable, die ein Zeilentrigger ändert, gegen den zweiten Punkt, kann das Verhalten bereits nicht deterministisch sein. Bewahren Sie beobachtete Resultate für die Parität, kennzeichnen Sie die Abhängigkeit aber für eine ausdrückliche Neugestaltung, statt sie als Anforderung abzusegnen.

Auch die Package-Initialisierung ist ein oft übersehener Einstiegspunkt. Oracle führt den Initialisierungsteil eines Package-Bodys aus, wenn eine Sitzung erstmals auf das Package zugreift. Lädt er Konfiguration, ermittelt ein Geschäftsdatum oder setzt eine Package-Variable, besitzt der erste öffentliche Prozeduraufruf einen unsichtbaren Vorspann. Untersuchen Sie den abschließenden Bereich BEGIN ... END jedes Bodys und erfassen Sie dort Lese- und Schreibzugriffe, Fehler und Kontextabhängigkeiten.

Beenden Sie diesen Durchgang mit einem Aufrufgraphen, dessen Wurzeln betriebliche Ereignisse sind, nicht nur Objektnamen. Jede Wurzel sollte den auslösenden Akteur, die Transaktion, Eingabeform, erreichten Packages oder Trigger, gelesene und geschriebene Tabellen, externe Wirkungen und beobachtete Fehler nennen. Unbekannte Felder sind nützlich: Sie zeigen genau, wo Laufzeitbelege fehlen.

Überladene Package-Prozeduren brauchen Signaturen, nicht nur Namen. Erfassen Sie Argumentposition, Modus, Typ, Default-Status und Overload-Kennung aus ALL_ARGUMENTS, und gleichen Sie die Signaturen mit den Aufrufern ab. Treiber können nach Position binden, Oracle-Collection-Typen offenlegen oder von der Form eines OUT-Cursors abhängen. ORDER_API.SUBMIT durch einen HTTP-Endpunkt zu ersetzen ändert einen Schnittstellenvertrag, auch wenn das fachliche Ergebnis gleich bleibt. Katalogisieren Sie diese Kompatibilitätsarbeit getrennt von der Regelerfassung.

Statische Abhängigkeiten zeigen nicht das ganze Programm

Behandeln Sie ALL_DEPENDENCIES als nützliche Untergrenze, denn Oracle kann für einen Objektnamen, der in dynamischem SQL zusammengesetzt wird, keine normale Abhängigkeit zur Kompilierzeit speichern. Synonyme, Datenbanklinks, Namensauflösung mit Invoker-Rechten, Anwendungskontexte und in Tabellen gespeicherte Zeichenketten vergrößern die Lücke.

Beginnen Sie mit dem statischen Graphen:

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;

Durchsuchen Sie den Quelltext danach nach Verhalten, das der Graph nicht zuverlässig auflösen kann: EXECUTE IMMEDIATE, DBMS_SQL, OPEN ... FOR, Datenbanklink-Markierungen, SYS_CONTEXT, Pragmas für autonome Transaktionen, Datei- und Queue-Packages, Mail-Aufrufe sowie Fehlerbehandler mit Schreibzugriffen. Durchsuchen Sie Tabellendaten nach konfigurierten Prozedurnamen, wenn die Anwendung metadatengesteuert weiterleitet.

Dynamisches SQL braucht eine Prüfung der Herkunft jeder Zeichenkette. Bestimmen Sie für jede Anweisung das Template, alle eingesetzten Bezeichner, Bind-Werte, das Schema zur Namensauflösung und zur Laufzeit erfasste Beispiele. Eine Zeile wie EXECUTE IMMEDIATE l_sql USING p_id sagt wenig aus, solange Sie nicht wissen, ob l_sql eine bekannte Partition aktualisiert oder ein mandantenspezifisches Package aufruft, das aus einer Konfigurationstabelle gewählt wird.

Auch Berechtigungsverhalten gehört in diese Analyse. Ein Package ohne ausdrückliches AUTHID CURRENT_USER verwendet standardmäßig Definer-Rechte. Seine unqualifizierten Objektreferenzen und Berechtigungen verhalten sich daher nicht wie eine Serviceabfrage unter der Identität eines Endbenutzers. Erfassen Sie AUTHID, direkte Grants, Rollen, Synonyme und Zugriffe auf den Anwendungskontext. Wird die Routine in einen Anwendungsservice verlegt, kann ungewollt eine berechtigte Autoritätsgrenze verschwinden oder das Servicekonto weit mehr Zugriff erhalten, als das Package je hatte.

Instrumentieren Sie nicht als Reaktion jede Zeile. Beobachten Sie die Grenzen: Ein- und Austritt aus Packages, Transaktionsergebnis, Triggerauslösung, Form dynamischer Anweisungen und externe Aufrufe. Verwenden Sie eine Korrelationskennung, die von der Anwendungsanfrage bis in die Sitzungsmetadaten der Datenbank erhalten bleibt. Erfassen Sie Bind-Werte nur, soweit Richtlinien es erlauben, und schwärzen Sie sensible Felder vor der Speicherung. Ziel ist eine Verhaltenskarte und keine zweite Produktionsdatenbank voller Geheimnisse.

Statische Analyse übertreibt manche Abhängigkeiten ebenfalls. Ein Package-Body kann aufgegebene Routinen enthalten, die seit Jahren ungenutzte Tabellen referenzieren. Jede Kante als aktiv zu markieren lässt den Migrationsumfang schneller wachsen als die Belege. Führen Sie getrennte Graphen für "kann aufrufen" und "hat aufgerufen", und speichern Sie beim zweiten Beobachtungszeitraum und Arbeitslast. Das Fehlen in einem Trace beweist keinen toten Code, rechtfertigt aber die Forderung nach einem Besitzer oder einem entworfenen Test, bevor der Pfad neu gebaut wird.

Entdeckungen in ein Verhaltensregister überführen

Ein Verhaltensregister macht aus Quellcodefunden testbare Verträge. Eine Zeile beschreibt eine extern bedeutsame Regel mit Eingaben, Ausgaben, Zustandsänderungen, Fehlerverhalten und Belegen. Ohne dieses Zwischenartefakt ordnen Architekten häufig ganze Packages Zielkomponenten zu und übertragen zufällige Grenzen in den Ersatz.

Betrachten Sie eine Package-Prozedur, die eine Rechnung bestätigt. Sie prüft den Status, ermittelt Steuern aus Kunden- und Gültigkeitstabellen, fügt Hauptbuchzeilen ein, ändert den Rechnungsstatus und stellt eine Benachrichtigung in eine Queue. Das ist keine einzelne Regel. Das Register sollte Zulässigkeit, Steuerauswahl, Buchung, Statusübergang und Benachrichtigungsabsicht trennen, weil jede davon ein anderes Ziel und ein anderes Testorakel verdienen kann.

Ein brauchbarer Registereintrag enthält:

  • Regelkennung und eine allgemein verständliche Aussage mit Quellort
  • Auslösendes Ereignis sowie nötigen Sitzungs-, Tabellen- und Package-Zustand
  • Eingaben, Ausgaben, Schreibvorgänge, Nachrichten, Dateien und Commits oder Rollbacks
  • Grenzfälle, Oracle-Fehler, eigene Fehlercodes und Wiederholungsverhalten
  • Belege aus Quelle, Traces, Produktionsbeispielen und einem genehmigenden Verantwortlichen

Geben Sie jeder Regel einen Status wie beobachtet, abgeleitet, umstritten, genehmigt oder veraltet. Quellcode allein rechtfertigt "abgeleitet", wenn der Zweig unerreichbar sein könnte. Eine erfasste Ausführung rechtfertigt "beobachtet". Finanzen oder Betrieb können genehmigen, ob ein seltsames Verhalten vertraglich gilt. Das verhindert die typische Besprechung, in der ein überraschendes Ergebnis nur deshalb zum Fehler erklärt wird, weil der neue Entwurf es nicht reproduziert.

Trennen Sie Geschäftsregeln von Datenbankmechanik. "Eine Rechnung darf nicht in eine geschlossene Periode gebucht werden" ist eine Regel. "Ein BEFORE INSERT-Trigger fragt PERIOD_CONTROL ab und löst -20041 aus" ist eine Implementierung. "Setze UPDATED_AT aus SYSTIMESTAMP" kann eine Persistenzrichtlinie sein. "Erhöhe eine Package-Globalvariable" kann ein Workaround sein. Die Folge ist entscheidend: Migrieren Sie die Regel, testen Sie den alten Mechanismus und behalten Sie ihn nur, wenn seine Semantik Teil des Vertrags ist.

Erfassen Sie auch den Negativraum. Umgehen direkte SQL-Updates eine Anwendungsvalidierung, treffen aber weiterhin einen Trigger, definiert dieser Trigger die tatsächliche Durchsetzungsgrenze. Führt ein Package intern einen Commit aus, können Aufrufer den gesamten Ablauf nicht zurückrollen, selbst wenn ihr Code scheinbar die Transaktion besitzt. Diese unbequemen Tatsachen bestimmen den Cutover und dürfen nicht in Architekturprosa geglättet werden.

Machen Sie Meinungsverschiedenheiten nach Möglichkeit ausführbar. Wenn der Betrieb sagt, eine rückdatierte Stornierung sei erlaubt, und die Finanzabteilung widerspricht, bewahren Sie beide Beispielkandidaten, erwartete Resultate und zugrunde liegende Datenbedingungen auf. Lassen Sie den Verantwortlichen ein Ergebnis im Register genehmigen. Eine Prosa-Anforderung wie "Rückdatierung korrekt behandeln" übersteht jede Prüfung, gibt dem Implementierungsteam aber nichts zum Vergleichen.

Das Register steuert auch Löschungen. Kann niemand einen auslösenden Akteur, eine beobachtete Ausführung, einen regulatorischen Grund oder ein genehmigtes Beispiel für eine Routine nennen, markieren Sie sie als Entfernungskandidaten. Bewahren Sie den alten Quelltext auf und beweisen Sie, dass kein Aufrufer sie erreicht. Verbringen Sie keine Migrationszeit mit ihrer Übersetzung, nur weil sie kompiliert.

Transaktionen statt isolierter Funktionen testen

Abläufe statt Syntax ersetzen
Der Rewrite verteilt Verhalten nach Verantwortung auf Go-Services, Rust-Kernel, TypeScript-Clients oder Postgres.

Charakterisierungstests sollten das alte System über seine echten öffentlichen Grenzen ansteuern und das vollständige Transaktionsergebnis vergleichen. Ein Unit-Test für eine private Steuerfunktion übersieht Trigger-Nebenwirkungen, Package-Zustand, NLS-Einstellungen, Sequenzverbrauch, Fehlerübersetzung und Commit-Verhalten.

Erstellen Sie eine temporäre Oracle-Testumgebung aus einem maskierten, referenziell konsistenten Datensatz. Setzen Sie Sitzungseingaben ausdrücklich: Zeitzone, NLS_DATE_FORMAT, numerische Zeichen, aktuelles Schema, Anwendungskontext und Quellen des Geschäftsdatums. Setzen Sie Tabellen und Sequenzen für jeden Fall auf einen bekannten Ausgangspunkt zurück, wenn exakte Kennungen wichtig sind. Verwenden Sie getrennte Sitzungen für Tests mit Package-Zustand.

Oracle dokumentiert, dass jede Sitzung eine eigene Package-Instanz erhält und Werte zustandsbehafteter Packages normalerweise für die Sitzung bestehen bleiben. Die Neukompilierung eines instanziierten zustandsbehafteten Packages kann diesen Zustand verwerfen und beim nächsten Aufruf ORA-04068 auslösen. Ein Connection Pool macht aus Package-Globalvariablen deshalb verborgenen Speicher je Verbindung. Ihre Suite braucht Fälle für eine frische Sitzung, wiederholte Aufrufe in derselben Sitzung, zwei gleichzeitige Sitzungen, Wiederverwendung einer Pool-Sitzung, Rollback und Package-Invalidierung, falls Produktions-Deployments sie auslösen können.

Erfassen Sie für jeden Test einen normalisierten Beobachtungssatz:

{
  "case": "closed-period-credit",
  "entry": "billing.invoice_api.post_credit",
  "result": {"status": "error", "oracle_code": -20041},
  "tables": {"invoice": [], "ledger_entry": []},
  "events": [],
  "transaction": "rolled_back"
}

Die neue Implementierung sollte dieselbe fachliche Beobachtung erzeugen, nicht zwingend denselben Oracle-Stack oder Sequenzwert. Normalisieren Sie erzeugte Kennungen auf stabile Aliase, vergleichen Sie Geld mit seiner festgelegten Skalierung, sortieren Sie Mengen nur bei vertraglicher Reihenfolge und vergleichen Sie Zeitstempel mit der Präzision, die die alte Schnittstelle offenlegte. Behalten Sie eigene Fehlercodes exakt bei, wenn Aufrufer danach verzweigen. Andernfalls ordnen Sie sie an der Kompatibilitätsgrenze einem ausdrücklichen Domänenfehler zu und testen die Zuordnung.

Testen Sie Fehler und Teilarbeit absichtlich. Erzwingen Sie nach einem Audit-Insert eine doppelte Kennung. Machen Sie die Benachrichtigungs-Queue unerreichbar. Lösen Sie nach der Verarbeitung mehrerer Zeilen in einem Zeilentrigger einen Fehler aus. Prüfen Sie Bulk-DML, bei dem das Timing von Statement- und Zeilentriggern bestimmt, was bestehen bleibt. Ein erfolgreicher Prozeduraufruf zeigt keine autonome Transaktion, die eine Audit-Zeile schrieb, obwohl die Geschäftstransaktion zurückgerollt wurde.

Ein häufiger Fehler sieht so aus: Eine Anwendung beginnt eine Transaktion, ruft ein Package zur Kreditreservierung auf, fügt einen Auftrag ein und rollt zurück, weil die Bestandszuweisung fehlschlägt. Das Package aktualisiert einen globalen Cache für "verfügbaren Kredit", und eine autonome Audit-Routine committet einen Reservierungseintrag. Das Tabellenupdate wird zurückgerollt, aber der Package-Wert bleibt in dieser Pool-Sitzung und der Audit-Eintrag bleibt committet. Ein Ersatz, der alles in eine saubere Service-Transaktion fasst, verhält sich bei der nächsten Anfrage anders. Das Register muss festlegen, ob diese Reste erforderlich, tolerierte Defekte oder zu entfernendes Verhalten sind, und die Testsuite muss die genehmigte Wahl festhalten.

Die Triggerreihenfolge braucht eigene Fälle, wenn mehrere Trigger dieselbe Tabelle und denselben Zeitpunkt teilen. Oracle bietet FOLLOWS und in begrenzten Fällen PRECEDES für deklarierte Beziehungen, doch unverbundene Trigger erhalten keine verlässliche Gesamtordnung. Erfassen Sie die DDL und testen Sie Endergebnisse unter Anweisungen mit mehreren Zeilen. Schreiben Sie keinen Zieltest, der eine zufällige Ausführungsfolge verlangt, sofern die Quelle sie nicht ausdrücklich deklariert und das Geschäftsergebnis davon abhängt.

Messen Sie Abdeckung nach Registerregeln und Einstiegspunkten, nicht nach PL/SQL-Zeilen. Ein Test kann jede Zeile eines Steuer-Packages ausführen, ohne zu beweisen, welcher Satz an einer Gültigkeitsgrenze gewinnt. Umgekehrt kann eine kompakte Matrix aus Daten, Rechtsgebieten, Kundenklassen und Stornierungszuständen den Vertrag charakterisieren, während defensive Zweige unbesucht bleiben. Nutzen Sie gewöhnliche Codeabdeckung als Diagnose, nicht als Abnahmekriterium.

Produktionsverkehr liefert Fälle, nicht die Wahrheit

Aufgezeichneter Produktionsverkehr ist die stärkste Quelle realistischer Eingaben, definiert aber nicht die vollständige Spezifikation. Er enthält überproportional viele Normalfälle, historische Zufälle und selten jene Gegenbeispiele, die scheitern sollten.

Zeichnen Sie Anfragen an der Grenze auf, an der die Bedeutung der Eingabe noch sichtbar ist. Speichern Sie aufgerufene Operation, geordnete Aufrufe innerhalb einer Transaktion, bereinigte Parameter, relevanten Sitzungskontext, Ergebnisklasse und Kennungen zum Einsammeln betroffener Zeilen. Erfassen Sie für SQL-getriebene Einstiegspunkte Bind-Werte und Transaktionsgruppierung statt nur rohen SQL-Text. Bewahren Sie für Batch-Arbeit Dateiform und Kontrollsummen, ohne eingeschränkte Nutzdaten in einen unkontrollierten Testspeicher zu kopieren.

Spielen Sie jeden Fall gegen alte und neue Implementierung aus gleichwertigem Ausgangszustand ab. Vergleichen Sie Rückgabewerte, Fehler, Datenbankänderungen, gesendete Ereignisse und Commit-Grenzen. Wenn Ergebnisse abweichen, klassifizieren Sie den Grund, bevor Sie Code ändern: fehlende Regel, beabsichtigte Neugestaltung, Nichtdeterminismus, fehlerhafte Testdaten oder ein alter Defekt, den der Verantwortliche aufgeben will.

Verkehr muss durch entworfene Fälle aus dem Register ergänzt werden. Fügen Sie Grenzdaten, Nullwerte, doppelte Anfragen, Wiederholungen nach Timeout, maximal unterstützte numerische Skalierung, unberechtigte Benutzer, geschlossene Buchungsperioden und gleichzeitige Änderungen derselben Entität hinzu. Ergänzen Sie metamorphische Prüfungen, wenn sich ein exaktes Ergebnis schwer aufzählen lässt. Das Buchen und anschließende Stornieren einer zulässigen Rechnung sollte ihre Nettowirkung im Hauptbuch beispielsweise auf null bringen, vorbehaltlich der alten Rundungsregel.

Wählen Sie Stichproben nach Verhalten und Volumen. Eine Million erfolgreiche Auftragseinreichungen bringt wenig zusätzliche Evidenz, sobald sich die Eingabeformen wiederholen. Ein Jahresabschluss, eine Zeitumstellung oder eine manuelle Korrektur kann dagegen einen einzigartigen Zweig abdecken. Bewahren Sie seltene Fälle bewusst auf und geben Sie ihnen stabile Testdaten. Die Produktionshäufigkeit sollte Performance-Tests lenken, geschäftliche Folgen und Einzigartigkeit eines Zweigs hingegen die Paritätsabdeckung.

CodeHero verwendet beim Rewrite von Systemen, einschließlich PL/SQL-Beständen, ein Paritäts-Testsystem mit aufgezeichnetem Produktionsverkehr und liest die Sprachen rund um den Datenbankcode als eine Codebasis. Das ist wichtig, weil der Vertrag einer Stored Procedure oft teilweise in einem Java-Aufrufer, einem Scheduler-Skript und den von einem Trigger geänderten Zeilen steckt. Das Testsystem braucht weiterhin die negativen Fälle und Grenzfälle des Registers; Abspielvolumen kann kein Verhalten beweisen, das im Verkehr nie vorkam.

Geben Sie erfasste Produktionseingaben nicht ohne Entscheidung zur Datenklassifizierung an ein Modell oder eine Testumgebung weiter. Maskierung muss Eigenschaften bewahren, die Regeln verwenden, etwa Gleichheitsgruppen, Datumsreihenfolge, Kontopräfixe und referenzielle Integrität. Jeden Wert durch zufälligen Text zu ersetzen kann Identitäten schützen und zugleich genau die Fälle zerstören, die die Migration testen muss.

Jede Regel an ihrer engsten verlässlichen Grenze platzieren

Den Rewrite intern ausführen
Regulierte Teams können die bereitgestellten CodeHero-Modelle air-gapped im eigenen Perimeter betreiben.

Platzieren Sie eine Regel dort, wo jeder relevante Schreibvorgang passieren muss und wo das Team sie beobachten und testen kann. Daraus entsteht meist eine geteilte Architektur statt einer Kampagne, sämtliches PL/SQL in Services zu verlagern oder alle Regeln in Postgres zu behalten.

Verwenden Sie Datenbank-Constraints für Invarianten, die sich gegen eine Zeile oder den relationalen Zustand ausdrücken lassen: Nullfähigkeit, Eindeutigkeit, Fremdschlüssel und prüfbare Wertebereiche. Constraints decken jeden Schreiber ab und liefern dem Query-Planer nützliche Fakten. Ersetzen Sie kein deklaratives Constraint durch Anwendungscode, nur weil sich dieser leichter versionieren lässt.

Behalten Sie eine kleine Datenbankfunktion oder einen Trigger nur, wenn die Regel wirklich für alle Schreiber gilt, sich nicht deklarativ ausdrücken lässt und diese Schreiber weiterhin einen einzelnen Service umgehen. Machen Sie Nebenwirkungen ausdrücklich und klein. Ein Trigger, der Audit-Kontext stempelt, kann vertretbar sein. Ein Trigger, der Preise berechnet, fünf Tabellen beschreibt, eine Nachricht sendet und autonom committet, verbirgt einen Ablauf, der eine verantwortete API braucht.

Legen Sie Ablaufregeln in einen Service, wenn sie Aggregate koordinieren, externe Systeme aufrufen, ausdrückliche Wiederholungen brauchen oder Produktbeobachtung erfordern. Der Service sollte die Transaktion besitzen oder für Arbeit nach dem Commit ein Outbox-Muster verwenden. Veröffentlichen Sie keine Nachricht vor dem Datenbank-Commit in der Hoffnung, Verbraucher würden einen Rollback verkraften. Lassen Sie nicht gleichzeitig den Kompatibilitätstrigger und den neuen Service senden.

Legen Sie numerische Kerne nur dann in Rust, wenn die Arbeit von einer engen, unabhängig testbaren Berechnungsgrenze profitiert. Legen Sie Darstellungsregeln nur dann in TypeScript-Clients, wenn Server oder Datenbank die zugrunde liegende Invariante weiterhin erzwingen. Eine deaktivierte Schaltfläche gibt nützliches Feedback; sie ist keine Autorisierung.

Postgres ist nicht Oracle mit anderer Schreibweise. Package-Sitzungszustand hat kein natürliches Gegenstück, leere Zeichenketten und Nullwerte unterscheiden sich, Fehler und autonome Transaktionen verhalten sich anders, und die Triggerreihenfolge braucht einen ausdrücklichen Entwurf. Modernisieren Sie diese Grenzen, statt sie zu transliterieren. Eine ausdrückliche Serviceanfrage, Transaktion und ein Outbox-Eintrag sind leichter zu verstehen als ein neues Netz verborgener Rückrufe.

Ein Entscheidungsprotokoll für jede Registerregel sollte gewählten Besitzer, Durchsetzungspunkt, Kompatibilitätsplan, Testfälle und Entfernungsbedingung für die Oracle-Implementierung nennen. Hat eine Regel keinen Besitzer, ist sie nicht umgezogen. Erzwingen zwei Komponenten sie, dokumentieren Sie, welche maßgeblich ist und wie lange die Dopplung besteht.

Beim Cutover Regeln nicht doppelt ausführen

Gemischte Legacy-Bestände verfolgen
Die Plattform liest PL/SQL neben jeder aufrufenden Sprache, auch in Systemen mit Millionen Zeilen.

Das größte Cutover-Risiko ist doppeltes Verhalten: Der neue Service führt eine Regel aus, während ein alter Trigger sie unbemerkt noch einmal ausführt. So entstehen doppelte Hauptbuchzeilen, wiederholte Benachrichtigungen, widersprüchliche Zeitstempel oder ein Update, das einen Validator besteht und am anderen scheitert.

Erstellen Sie eine Aktivierungsmatrix je Regel. Die Zeilen sind Kennungen aus dem Verhaltensregister. Die Spalten sind alte Anwendung, Oracle-Package, Oracle-Trigger, neuer Service, Postgres-Constraint oder -Trigger und Ereignisverbraucher. Markieren Sie für jeden Rollout-Zustand genau einen maßgeblichen Ausführer und etwaige Beobachter. Lehnen Sie einen Zustand mit zwei Ausführern ab, sofern die Operation nicht nachweislich idempotent und die Dopplung beabsichtigt ist.

Schattenausführung darf gemeinsamen Produktionszustand nicht ändern. Lassen Sie die neue Entscheidungslogik im Beobachtungsmodus laufen oder spielen Sie erfasste Eingaben gegen ein isoliertes Ziel ab. Vergleichen Sie danach ihr vorgeschlagenes Ergebnis mit Oracles committetem Ergebnis. Ersetzen Sie bei Abläufen mit externen Wirkungen das Ziel durch eine Senke, die Absichten aufzeichnet, ohne Mail zu senden, ein Konto zu belasten oder in ein Live-Topic zu veröffentlichen.

Dual Writes sind beliebt, weil sie Rollbacks einfach erscheinen lassen. Meist erzeugen sie zwei Fehlerarten und eine mehrdeutige Quelle der Wahrheit. Bevorzugen Sie einen Schreiber plus Change Capture oder Outbox, mit gemessener Replikationsverzögerung und Abgleichsabfrage. Sind vorübergehende Dual Writes unvermeidbar, vergeben Sie an der ursprünglichen Anfragegrenze einen Idempotenzschlüssel und speichern Sie das Ergebnis auf beiden Seiten.

Schalten Sie nach zusammenhängendem Einstiegspunkt um, nicht nach willkürlicher Package-Datei. Verschieben Sie Prozedur, abhängige Trigger, Transaktionssemantik und nachgelagerte Wirkungen als einen Verhaltensausschnitt. Sperren oder routen Sie direkte Schreiber um, die die neue Autorität umgehen würden. Behalten Sie eine Kompatibilitätsfassade nur, wenn Aufrufer Zeit für den Wechsel brauchen, und lassen Sie diese den neuen Besitzer aufrufen statt eine zweite Implementierung zu enthalten.

Ein Rollback muss die Datenrichtung angeben, nicht nur die Deployment-Richtung. Legen Sie fest, welches System maßgeblich bleibt, welche Schreibvorgänge pausieren, wie reine Zieldatensätze bei Bedarf zu Oracle zurückkehren und wie ausgesendete Wirkungen abgeglichen werden. Ein Container-Rollback ist kein fachlicher Rollback, nachdem Geld, Nachrichten oder Dateien die Transaktion verlassen haben.

Oracles Abschaltung ist ein Abnahmetest

Eine PL/SQL-Migration ist beendet, wenn das Unternehmen mit abgeschaltetem relevantem Oracle-Verhalten arbeiten kann und das Team belegen kann, warum die Ergebnisse weiterhin stimmen. "Alle Package-Bodys übersetzt" sagt nichts über Trigger, Jobs, Sitzungsglobalen, Betriebsskripte oder Aufrufer aus, die sich noch direkt verbinden.

Fordern Sie für jeden Einstiegspunkt eine geschlossene Kette vom auslösenden Akteur über eine genehmigte Registerregel und einen Zielbesitzer bis zu bestandenen Charakterisierungsfällen, Cutover-Zustand und Produktionsbeobachtung. Wiederholen Sie die Schemainventur und vergleichen Sie sie mit dem Ausgangssnapshot. Jeder verbleibende aktivierte Trigger, ausführbare Grant, Scheduler-Job, jedes Synonym und jede Anwendungsverbindung braucht einen ausdrücklichen Grund.

Führen Sie danach in einer produktionsnahen Umgebung einen Verweigerungstest durch. Entziehen Sie den alten Ausführungspfad oder deaktivieren Sie den migrierten Trigger, führen Sie die vollständige Verkehrs- und Fallsuite aus und überwachen Sie Verbindungsversuche. Der Test muss scheitern, wenn noch ein Pfad von Oracle abhängt. Ein erfolgreicher Lauf liefert stärkere Belege als eine Tabelle, in der jeder Komponentenverantwortliche eine Zeile als erledigt markiert hat.

Bewahren Sie Quellsnapshot, Verhaltensregister, normalisierte Beobachtungen, Entscheidungsprotokolle und Paritätsergebnisse als gemeinsamen Belegsatz auf. Sie erklären mehr als die Arbeitsweise des alten Codes. Sie zeigen, welche Merkwürdigkeiten das Unternehmen akzeptierte, welche Defekte es aufgab und wo jede verbleibende Regel nun liegt.

CodeHero liefert Legacy-Rewrites in weniger als 30 Tagen, aber Geschwindigkeit entschuldigt kein Raten über Datenbankverhalten. Schnell wird eine Migration, wenn das gesamte System gleichzeitig untersucht wird, Entdeckungen in ausführbare Vergleiche übergehen und eine Regel erst als migriert zählt, wenn Oracle sie nicht mehr erzwingen muss.

FAQ

Wie finde ich den gesamten PL/SQL-Code in einer Oracle-Datenbank?

Fragen Sie DBA_SOURCE oder ALL_SOURCE nach Packages, Package-Bodys, Prozeduren, Funktionen, Triggern und Typen ab, und extrahieren Sie ihre DDL mit DBMS_METADATA. Nehmen Sie auch Jobs, Grants, Synonyme, ungültige Objekte, virtuelle Spalten, funktionsbasierte Indizes und Richtlinien auf, denn Quelltext allein beschreibt nicht jeden Aufrufpfad.

Findet ALL_DEPENDENCIES jede PL/SQL-Abhängigkeit?

Nein. Die View erfasst normale Abhängigkeiten zur Kompilierzeit, doch dynamisches SQL, konfigurierte Objektnamen, Synonyme, Datenbanklinks, Auflösung mit Invoker-Rechten und externe Aufrufe können dem Graphen entgehen. Kombinieren Sie ihn mit Quelltextsuchen und Laufzeit-Traces.

Sollte Geschäftslogik aus Datenbanktriggern entfernt werden?

Verschieben Sie Abläufe und externe Nebenwirkungen in einen verantworteten Service, aber behalten Sie universelle Invarianten an der engsten Grenze, die jeder Schreiber passieren muss. Ein deklaratives Datenbank-Constraint ist meist besser als ein Trigger oder doppelte Prüfungen im Anwendungscode.

Wie teste ich ein PL/SQL-Package vor dem Rewrite?

Rufen Sie seine öffentlichen Einstiegspunkte gegen einen kontrollierten Oracle-Datensatz auf und erfassen Sie Rückgabewerte, Fehler, Tabellenänderungen, Ereignisse und Transaktionsergebnisse. Wiederholen Sie Fälle in frischen, wiederverwendeten, gleichzeitigen und invalidierten Sitzungen, wenn das Package Zustand hält.

Warum ist Oracle-Package-Zustand bei einer Migration wichtig?

Package-Variablen können für die Lebensdauer einer Datenbanksitzung bestehen bleiben, sodass ein Connection Pool verborgenen Zustand zwischen Anfragen trägt. Ein zustandsloser Ersatz kann das Verhalten ändern, sofern Tests diese Abhängigkeit nicht aufdecken und Verantwortliche nicht über Erhalt oder Entfernung entscheiden.

Reicht Produktionsverkehr zum Nachweis der PL/SQL-Parität?

Nein. Replay liefert realistische Eingaben, übersieht aber seltene Fehler, Grenzdaten, unberechtigte Aufrufe und Zweige, die der aktuelle Verkehr nie nimmt. Ergänzen Sie entworfene Fälle aus einem Verhaltensregister und vergleichen Sie vollständige Transaktionswirkungen.

Wie sollten autonome Transaktionen migriert werden?

Klären Sie zuerst, warum der alte Code Arbeit unabhängig committet und ob das Unternehmen auf ihr Fortbestehen nach einem Rollback angewiesen ist. Die meisten Audit- oder Messaging-Fälle werden als ausdrückliche Outbox oder getrennt verantworteter Schreibvorgang klarer, doch das genehmigte Verhalten muss den Entwurf bestimmen.

Kann Oracle PL/SQL direkt nach PostgreSQL übersetzt werden?

Syntax lässt sich umwandeln, aber eine direkte Übersetzung übersieht semantische Unterschiede bei Package-Zustand, Nullwerten und Leerstrings, Fehlern, Rechten, Transaktionen und Triggern. Erfassen Sie zuerst das Verhalten und wählen Sie dann für jede Regel einen nativen Besitzer.

Wie verhindere ich doppelte Triggerwirkungen beim Cutover?

Führen Sie eine Aktivierungsmatrix mit genau einem maßgeblichen Ausführer für jede Regel im Verhaltensregister. Lassen Sie die neue Logik ohne gemeinsame Änderungen im Schatten laufen und deaktivieren oder umgehen Sie den alten Ausführer, sobald der neue Pfad schreibt.

Wann ist eine PL/SQL-Migration wirklich abgeschlossen?

Sie ist abgeschlossen, wenn migrierte Oracle-Pfade deaktiviert werden können und Verkehrs-Replay sowie entworfene Fälle weiterhin bestehen. Verbleibende Trigger, Jobs, Grants, Synonyme und Direktverbindungen brauchen jeweils einen ausdrücklichen Besitzer und Existenzgrund.