Aller au contenu
14 août 2026·8 min de lecture

Comment retrouver les règles cachées d'une migration PL/SQL

Une migration PL/SQL réussit en recensant packages, triggers, états de session et effets, puis en prouvant la parité avant de déplacer chaque règle.

Comment retrouver les règles cachées d'une migration PL/SQL

Le danger d'une migration PL/SQL ne réside pas dans la conversion de la syntaxe. Il consiste à découvrir les comportements de la base dont l'entreprise dépend avant que l'ancienne base cesse de les fournir. Les corps de packages, les triggers par ligne et par instruction, les appels planifiés, l'état de session et les chemins d'erreur peuvent porter des règles absentes de tous les dépôts applicatifs.

Une migration crédible traite le schéma Oracle comme un système exécutable, et non comme un bac de procédures stockées. L'inventaire établit ce qui existe. Le traçage établit ce qui s'exécute. Les tests de caractérisation établissent ce que cela signifie. L'équipe peut alors décider si une règle doit vivre dans un service Go, un noyau Rust, un client TypeScript, une contrainte Postgres, ou nulle part.

Inventorier le schéma comme un système exécutable

Commencez par une extraction reproductible depuis une base semblable à la production, car une copie du dépôt correspond rarement à ce qu'Oracle exécute. Des correctifs urgents sont compilés depuis un poste de travail, des objets avec éditions se cachent derrière des synonymes et les autorisations déterminent les tables que le code exécuté avec les droits du définisseur peut toucher. Exportez DDL, source, statut, métadonnées des triggers, tâches, synonymes, autorisations et dépendances dans un instantané horodaté.

La vue Oracle ALL_SOURCE expose le texte source des procédures, fonctions, packages, corps de packages, triggers, types et corps de types accessibles. Utilisez DBA_SOURCE si le compte d'analyse possède le privilège requis et si le périmètre couvre plusieurs schémas. La requête suivante produit un inventaire stable, plutôt qu'un répertoire rempli de fichiers anonymes :

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;

La sortie contient une ligne par objet stocké : OWNER, TYPE, NAME et SOURCE_LINES. Un package apparaît dans deux lignes distinctes, PACKAGE et PACKAGE BODY. Ne les fusionnez pas. La spécification est un contrat public; le corps contient les routines privées, le code d'initialisation et la plupart des détails d'implémentation.

Extrayez le DDL de création en plus du texte. DBMS_METADATA.GET_DDL conserve des détails propres à l'objet que la concaténation de ALL_SOURCE.TEXT perd. Pour un package, demandez PACKAGE_SPEC et PACKAGE_BODY; pour un trigger, demandez TRIGGER. Enregistrez la version de la base, le schéma, le statut de l'objet, l'édition et l'heure d'extraction avec chaque fichier. L'équipe doit pouvoir dire quelle définition compilée a produit un résultat capturé.

Incluez les objets invalides et les erreurs de compilation au lieu de les filtrer. Un trigger invalide peut encore bloquer l'instruction qui le déclenche. Un package invalidé par une modification de table peut se recompiler à la demande dans des conditions que le dépôt source n'a jamais reproduites. DBA_OBJECTS.STATUS et DBA_ERRORS transforment ces conditions en preuves. Inventoriez aussi les vues matérialisées, colonnes virtuelles, index basés sur des fonctions, stratégies de contrôle d'accès fin et expressions par défaut qui appellent des fonctions. Tous ne sont pas des conteneurs PL/SQL, mais chacun peut invoquer une logique stockée ou en dépendre.

Prenez un second instantané après la période d'observation. La différence révèle souvent des outils de déploiement, des tâches nocturnes ou des administrateurs qui remplacent les corps de packages hors du processus de livraison officiel. Ne lancez pas une réécriture contre une cible mouvante sans geler ces changements ou les intégrer à l'extraction et aux tests.

Le nombre d'objets ne mesure pas le risque. Un trigger de six lignes qui change discrètement une période comptable peut compter davantage qu'un package de reporting de 9 000 lignes. L'inventaire délimite la recherche et détecte les écarts; il n'indique pas quel code porte le sens métier.

Trouver les points d'entrée avant de lire les packages

Identifiez qui peut invoquer PL/SQL et quels événements de base le déclenchent, puis lisez le code depuis ces points d'entrée vers l'intérieur. Lire les packages par ordre alphabétique gaspille du temps, car les utilitaires privés et le code mort paraissent aussi importants que les chemins suivis pour chaque commande.

Construisez une table des points d'entrée à partir d'au moins ces sources :

  • Appels applicatifs contenant des blocs anonymes, CALL ou des noms qualifiés de procédures de package
  • Triggers DML, DDL, de connexion, de démarrage et instead-of activés
  • Tâches du planificateur et entrées de l'ancienne file de tâches
  • Vues et fonctions appelées depuis des instructions SQL
  • Outils externes, rapports, chargeurs de fichiers et scripts d'exploitation

Pour les triggers, capturez davantage que le corps. Interrogez DBA_TRIGGERS sur TRIGGERING_EVENT, TRIGGER_TYPE, TABLE_OWNER, TABLE_NAME, STATUS, WHEN_CLAUSE et ACTION_TYPE. Reliez cet inventaire aux tables écrites par chaque parcours applicatif. Une règle attachée à ORDERS peut s'exécuter lorsqu'un script de support modifie la table, même si le service principal ne nomme jamais le trigger.

La documentation Oracle sur les triggers PL/SQL formule deux points qui affectent la migration. Un trigger s'exécute automatiquement pour l'événement défini, quel que soit l'utilisateur ou l'application qui émet l'instruction. Le code ne doit pas dépendre de l'ordre dans lequel une instruction SQL traite les lignes. Si le système existant enfreint ce second point au moyen d'une variable globale de package modifiée par un trigger de ligne, le comportement peut déjà être non déterministe. Préservez les résultats observés pour la parité, mais marquez cette dépendance pour une refonte explicite au lieu de la consacrer comme exigence.

L'initialisation d'un package est un autre point d'entrée souvent oublié. Oracle exécute la partie d'initialisation du corps lorsqu'une session référence ce package pour la première fois. Si elle charge une configuration, calcule une date métier ou définit une variable de package, le premier appel public possède un prélude invisible. Examinez la zone finale BEGIN ... END de chaque corps et consignez ses lectures, écritures, exceptions et dépendances au contexte.

Terminez par un graphe d'appels dont les racines sont des événements opérationnels, et non de simples noms d'objets. Chaque racine doit nommer l'acteur initiateur, la transaction, la forme d'entrée, le package ou trigger atteint, les tables lues et écrites, les effets externes et les erreurs observées. Les cases inconnues sont utiles : elles montrent exactement où les preuves d'exécution manquent.

Les procédures de package surchargées exigent des signatures, pas seulement des noms. Récupérez dans ALL_ARGUMENTS la position, le mode et le type de chaque argument, la présence d'une valeur par défaut et l'identifiant de surcharge, puis rapprochez ces signatures des appelants. Les pilotes peuvent lier par position, exposer des collections Oracle ou dépendre de la forme d'un curseur OUT. Remplacer ORDER_API.SUBMIT par un point de terminaison HTTP change un contrat d'échange même si le résultat métier reste identique. Inventoriez ce travail de compatibilité séparément de la récupération des règles.

Les dépendances statiques ne montrent pas tout le programme

Considérez ALL_DEPENDENCIES comme une borne inférieure utile, car Oracle ne peut pas enregistrer une dépendance normale de compilation pour un nom d'objet assemblé dans du SQL dynamique. Les synonymes, liens de base, résolutions avec les droits de l'appelant, contextes applicatifs et chaînes stockées dans des tables creusent l'écart.

Commencez par le graphe statique :

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;

Recherchez ensuite dans le source les comportements que le graphe ne résout pas de façon fiable : EXECUTE IMMEDIATE, DBMS_SQL, OPEN ... FOR, marqueurs de liens de base, SYS_CONTEXT, pragmas de transaction autonome, packages de fichiers et de files, appels de messagerie et gestionnaires d'exception qui écrivent. Si l'application distribue les appels à partir de métadonnées, recherchez aussi les noms de procédures configurés dans les données.

Le SQL dynamique demande de suivre la provenance des chaînes. Pour chaque instruction, identifiez le modèle, tous les identifiants substitués, les valeurs liées, le schéma utilisé pour résoudre les noms et des exemples capturés à l'exécution. Une ligne telle que EXECUTE IMMEDIATE l_sql USING p_id apporte peu tant que vous ignorez si l_sql met à jour une partition connue ou appelle un package propre à un locataire choisi dans une table de configuration.

Le comportement des privilèges appartient à la même analyse. Un package sans AUTHID CURRENT_USER explicite utilise par défaut les droits du définisseur. Ses références non qualifiées et ses autorisations ne se comportent donc pas comme une requête de service exécutée sous l'identité de l'utilisateur final. Consignez AUTHID, les autorisations directes, rôles, synonymes et lectures du contexte applicatif. Déplacer la routine dans un service peut supprimer par accident une frontière d'autorité légitime ou donner au compte de service bien plus d'accès que le package n'en possédait.

N'instrumentez pas chaque ligne. Observez les frontières : entrée et sortie de package, résultat de transaction, déclenchement des triggers, forme des instructions dynamiques et appels externes. Employez un identifiant de corrélation qui survive de la requête applicative aux métadonnées de session. Capturez les valeurs liées uniquement si la politique le permet et expurgez les champs sensibles avant stockage. L'objectif est une carte des comportements, pas une seconde base de production remplie de secrets.

L'analyse statique surestime aussi certaines dépendances. Le corps d'un package peut contenir des routines abandonnées qui référencent des tables inutilisées depuis des années. Marquer chaque arête comme active fait croître le périmètre plus vite que les preuves. Conservez deux graphes, « peut appeler » et « a appelé », avec la fenêtre d'observation et la charge associées au second. L'absence dans une trace ne prouve pas qu'un code est mort, mais justifie d'exiger un responsable ou un test conçu avant de reconstruire le chemin.

Transformer les découvertes en registre de comportements

Un registre de comportements transforme les constats du source en contrats testables. Chaque ligne décrit une règle significative de l'extérieur, avec ses entrées, sorties, changements d'état, échecs et preuves. Sans cet artefact intermédiaire, les architectes affectent volontiers des packages entiers à des composants cibles et transportent des frontières accidentelles dans le remplacement.

Prenons une procédure qui confirme une facture. Elle valide le statut, calcule la taxe depuis les tables client et date d'effet, insère des écritures comptables, modifie l'état de la facture et place une notification dans une file. Ce n'est pas une seule règle. Le registre doit séparer l'éligibilité, le choix fiscal, la comptabilisation, la transition d'état et l'intention de notification, car chacun peut mériter une cible et un oracle de test différents.

Une ligne utile du registre contient :

  • L'identifiant de règle et un énoncé simple avec son emplacement source
  • L'événement déclencheur et les états de session, table et package nécessaires
  • Les entrées, sorties, écritures, messages, fichiers, validations et annulations
  • Les cas limites, erreurs Oracle, codes d'erreur personnalisés et règles de nouvelle tentative
  • Les preuves issues du source, des traces, d'exemples de production et d'un responsable qui approuve

Attribuez à chaque règle un statut : observée, déduite, contestée, approuvée ou obsolète. Le source seul justifie « déduite » si la branche peut être inaccessible. Une exécution capturée justifie « observée ». La finance ou l'exploitation peut approuver le caractère contractuel d'un résultat étrange. Cela évite la réunion classique où un résultat surprenant devient un bug uniquement parce que la nouvelle conception ne l'a pas reproduit.

Séparez les règles métier de la mécanique de base. « Une facture ne peut pas être comptabilisée dans une période close » est une règle. « Un trigger BEFORE INSERT interroge PERIOD_CONTROL et lève -20041 » est une implémentation. « Définir UPDATED_AT depuis SYSTIMESTAMP » peut être une politique de persistance. « Incrémenter une globale de package » peut être un contournement. La conséquence compte : migrez la règle, testez l'ancien mécanisme et ne conservez ce mécanisme que si sa sémantique appartient au contrat.

Consignez aussi ce qui n'arrive pas. Si des mises à jour SQL directes contournent une validation applicative mais rencontrent encore un trigger, ce trigger définit la véritable frontière d'application. Si un package valide lui-même la transaction, l'appelant ne peut plus annuler tout le parcours même si son code semble posséder la transaction. Ces faits gênants déterminent la bascule et ne doivent pas être adoucis dans un texte d'architecture.

Rendez les désaccords exécutables quand c'est possible. Si l'exploitation autorise une annulation antidatée et que la finance l'interdit, conservez les deux exemples candidats, les résultats attendus et leurs conditions de données. Demandez au responsable d'approuver un résultat dans le registre. Une exigence comme « traiter correctement l'antidatage » survivra à toutes les revues sans rien donner de comparable à l'équipe de réalisation.

Le registre contrôle aussi la suppression. Si personne ne peut fournir un acteur appelant, une exécution observée, une raison réglementaire ou un exemple approuvé pour une routine, marquez-la comme candidate au retrait. Gardez l'ancien source et prouvez que les appelants ne l'atteignent pas. Ne dépensez pas du temps à la traduire uniquement parce qu'elle compile.

Tester les transactions plutôt que les fonctions isolées

Cartographier les appels PL/SQL
CodeHero lit ensemble packages, triggers, appelants et scripts avant d'attribuer chaque règle.

Les tests de caractérisation doivent piloter l'ancien système par ses véritables frontières publiques et comparer le résultat complet de la transaction. Tester unitairement une fonction fiscale privée manque les effets des triggers, l'état des packages, les paramètres NLS, la consommation des séquences, la traduction des exceptions et les validations.

Créez un environnement Oracle jetable à partir d'un jeu de données masqué et cohérent sur le plan référentiel. Fixez explicitement les entrées de session : fuseau horaire, NLS_DATE_FORMAT, caractères numériques, schéma courant, contexte applicatif et sources de date métier. Ramenez tables et séquences à un état connu pour chaque cas lorsque les identifiants exacts comptent. Utilisez des sessions séparées pour les tests qui impliquent l'état d'un package.

Oracle indique que chaque session reçoit sa propre instance de package et que l'état d'un package persiste normalement pendant la session. Recompiler un package avec état déjà instancié peut écarter cet état et provoquer ORA-04068 au prochain appel. Un pool de connexions transforme donc les variables globales de package en mémoire cachée propre à chaque connexion. Votre suite doit couvrir une session neuve, des appels répétés dans la même session, deux sessions concurrentes, la réutilisation d'une session du pool, une annulation et l'invalidation du package si les déploiements peuvent la provoquer.

Pour chaque test, capturez une observation normalisée :

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

La nouvelle implémentation doit produire la même observation métier, pas forcément la même pile Oracle ou la même valeur de séquence. Normalisez les identifiants générés en alias stables, comparez les montants à leur échelle déclarée, n'ordonnez les ensembles que si l'ordre est contractuel et comparez les horodatages à la précision exposée par l'ancienne interface. Conservez les codes d'erreur personnalisés exacts si les appelants bifurquent dessus; sinon, mappez-les vers une erreur de domaine explicite à la frontière de compatibilité et testez ce mappage.

Testez volontairement les échecs et le travail partiel. Forcez une clé dupliquée après une insertion d'audit. Rendez la file de notifications indisponible. Levez une exception depuis un trigger de ligne après le traitement de plusieurs lignes. Exercez le DML en masse, où le moment des triggers par instruction et par ligne change ce qui subsiste. Une procédure réussie ne révélera pas une transaction autonome qui a écrit une ligne d'audit alors que la transaction métier a été annulée.

Un échec fréquent se déroule ainsi : l'application commence une transaction, appelle un package pour réserver du crédit, insère une commande, puis annule lorsque l'allocation de stock échoue. Le package met à jour un cache global de « crédit disponible » et une routine d'audit autonome valide un enregistrement de réservation. La mise à jour de table est annulée, mais la valeur de package reste dans cette session du pool et l'audit reste validé. Un remplacement qui englobe tout dans une transaction de service propre se comportera autrement à la requête suivante. Le registre doit décider si ces traces sont requises, des défauts tolérés ou un comportement à supprimer, et la suite doit figer le choix approuvé.

L'ordre des triggers exige ses propres cas lorsque plusieurs triggers partagent une table et un point d'exécution. Oracle fournit les clauses FOLLOWS et, dans certains cas, PRECEDES pour les relations déclarées, mais des triggers sans relation n'obtiennent pas un ordre total fiable. Capturez le DDL et testez les résultats finaux avec des instructions multiligne. N'écrivez pas un test cible qui impose un ordre d'exécution accidentel, sauf si la source le déclare et si le résultat métier en dépend.

Mesurez la couverture par règles du registre et points d'entrée, pas par lignes PL/SQL. Un test peut parcourir chaque ligne d'un package fiscal sans prouver quel taux gagne à une limite de date d'effet. À l'inverse, une matrice compacte de dates, juridictions, catégories de clients et états d'annulation peut caractériser le contrat tout en laissant des branches défensives non visitées. Gardez la couverture de code ordinaire comme diagnostic, pas comme critère de réception.

Le trafic de production fournit des cas, pas la vérité

Le trafic de production enregistré est la meilleure source d'entrées réalistes, mais il ne définit pas toute la spécification. Il surreprésente les cas normaux, contient des accidents historiques et capture rarement les entrées contraires qui devraient échouer.

Enregistrez les requêtes à la frontière où le sens de l'entrée reste visible. Incluez l'opération appelée, l'ordre des appels dans une transaction, les paramètres assainis, le contexte de session pertinent, la catégorie du résultat et les identifiants nécessaires pour recueillir les lignes affectées. Pour les points d'entrée pilotés par SQL, enregistrez les valeurs liées et le groupement transactionnel plutôt que le seul texte SQL. Pour les traitements en lot, conservez la forme du fichier et les totaux de contrôle sans copier les données restreintes dans un stockage de test non contrôlé.

Rejouez chaque cas sur l'ancienne et la nouvelle implémentation depuis un état initial équivalent. Comparez valeurs de retour, erreurs, changements en base, événements émis et frontières de validation. Quand les résultats diffèrent, classez la raison avant de modifier le code : règle manquante, refonte intentionnelle, non-déterminisme, fixture erronée ou ancien défaut que le responsable décide d'abandonner.

Le trafic doit être complété par des cas conçus depuis le registre. Ajoutez dates limites, valeurs nulles, demandes dupliquées, nouvelles tentatives après expiration, échelle numérique maximale, utilisateurs non autorisés, périodes comptables closes et modifications concurrentes de la même entité. Ajoutez des vérifications métamorphiques si le résultat exact s'énumère mal. Par exemple, comptabiliser puis annuler une facture éligible doit ramener son effet comptable net à zéro, sous réserve de l'ancienne règle d'arrondi.

Échantillonnez par comportement autant que par volume. Un million de commandes réussies apporte peu de preuve une fois les formes d'entrée répétées, alors qu'une clôture annuelle, un changement d'heure ou un ajustement manuel peut couvrir une branche unique. Préservez volontairement les cas rares et donnez-leur des données stables. La fréquence de production doit guider les tests de performance; les conséquences métier et l'unicité des branches doivent guider la couverture de parité.

CodeHero utilise un banc de parité fondé sur le trafic de production enregistré pour réécrire des systèmes, y compris des patrimoines PL/SQL, et lit les langages autour du code de base comme un seul code source. C'est nécessaire, car le contrat d'une procédure stockée se trouve souvent en partie dans un appelant Java, un script planifié et les lignes modifiées par un trigger. Le banc a encore besoin des cas négatifs et limites du registre; le volume rejoué ne peut prouver un comportement que le trafic n'a jamais exercé.

N'envoyez pas d'entrées de production capturées à un modèle ou à un environnement de test sans décision de classification des données. Le masquage doit préserver les propriétés utilisées par les règles : groupes d'égalité, ordre des dates, préfixes de comptes et intégrité référentielle. Remplacer chaque valeur par du texte aléatoire peut protéger l'identité tout en détruisant les cas que la migration doit tester.

Placer chaque règle à sa frontière fiable la plus étroite

Trouver les règles hors application
CodeHero suit les triggers et la logique stockée que les dépôts applicatifs ne montrent jamais.

Placez une règle là où toute écriture concernée doit passer et où l'équipe peut l'observer et la tester. Cela produit généralement une architecture répartie, pas une campagne visant à déplacer tout PL/SQL dans des services ou à garder toutes les règles dans Postgres.

Utilisez les contraintes de base pour les invariants exprimables sur une ligne ou l'état relationnel : possibilité de valeur nulle, unicité, clés étrangères et plages de valeurs vérifiables. Les contraintes couvrent tous les auteurs d'écriture et donnent des faits utiles à l'optimiseur. Ne remplacez pas une contrainte déclarative par du code applicatif sous prétexte que ce code semble plus facile à versionner.

Ne gardez une petite fonction ou un trigger en base que si la règle s'applique réellement à tous les auteurs, ne peut être déclarée et si ces auteurs continueront à contourner un service unique. Rendez les effets explicites et minimaux. Un trigger qui inscrit le contexte d'audit peut se défendre; un trigger qui calcule un prix, écrit dans cinq tables, envoie un message et valide de façon autonome cache un parcours qui exige une API responsable.

Placez les règles de parcours dans un service lorsqu'elles coordonnent des agrégats, appellent des systèmes externes, exigent des nouvelles tentatives explicites ou nécessitent une observation au niveau produit. Le service doit posséder la transaction ou utiliser une boîte d'envoi pour le travail après validation. Ne publiez pas un message avant la validation en espérant que les consommateurs tolèrent une annulation. Ne laissez pas le trigger de compatibilité et le nouveau service l'émettre tous les deux.

Placez les noyaux numériques dans Rust seulement si le travail profite d'une frontière de calcul étroite et testable séparément. Placez les règles de présentation dans le client TypeScript seulement si le serveur ou la base continue à appliquer l'invariant sous-jacent. Un bouton désactivé donne une indication utile; ce n'est pas une autorisation.

Postgres n'est pas Oracle avec une autre orthographe. L'état de session des packages n'a pas d'équivalent naturel, les chaînes vides et les valeurs nulles diffèrent, les exceptions et transactions autonomes se comportent autrement, et l'ordre des triggers exige une conception explicite. Modernisez ces frontières au lieu de les translittérer. Une requête de service, une transaction et une ligne de boîte d'envoi explicites se comprennent mieux qu'un réseau recréé de rappels cachés.

Une décision pour chaque règle du registre doit nommer le propriétaire choisi, le point d'application, le plan de compatibilité, les cas de test et la condition de retrait de l'implémentation Oracle. Une règle sans propriétaire n'a pas déménagé. Si deux composants l'appliquent, documentez lequel fait autorité et combien de temps la duplication durera.

Basculer sans exécuter les règles deux fois

Conserver les preuves Oracle
Un banc de parité compare erreurs, écritures et transactions avant le retrait des anciens chemins.

Le principal risque de bascule est un comportement dupliqué : le nouveau service applique une règle tandis qu'un ancien trigger l'applique de nouveau sans bruit. Il en résulte des écritures comptables doublées, des notifications répétées, des horodatages contradictoires ou une mise à jour acceptée par un validateur et refusée par l'autre.

Construisez une matrice d'activation règle par règle. Les lignes sont les identifiants du registre. Les colonnes sont l'ancienne application, le package Oracle, le trigger Oracle, le nouveau service, la contrainte ou le trigger Postgres et le consommateur d'événements. Pour chaque état de déploiement, marquez un exécuteur faisant autorité et les éventuels observateurs. Refusez un état à deux exécuteurs sauf si l'opération est prouvée idempotente et si la duplication est intentionnelle.

Une exécution fantôme ne doit pas modifier l'état de production partagé. Faites tourner la nouvelle logique de décision en mode observation, ou rejouez les entrées capturées sur une cible isolée, puis comparez sa proposition au résultat validé par Oracle. Pour les parcours à effets externes, remplacez la destination par un récepteur qui enregistre l'intention sans envoyer de courriel, débiter un compte ou publier vers un sujet actif.

Les doubles écritures sont populaires parce qu'elles semblent faciliter le retour arrière. Elles créent généralement deux modes de panne et une source de vérité ambiguë. Préférez un seul auteur avec capture de changements ou boîte d'envoi, un retard de réplication mesuré et une requête de rapprochement. Si les doubles écritures temporaires sont inévitables, attribuez une clé d'idempotence à la frontière de la demande initiale et persistez le résultat des deux côtés.

Basculez par point d'entrée cohérent, pas par fichier de package arbitraire. Déplacez la procédure, les triggers dont elle dépend, sa sémantique transactionnelle et ses effets en aval comme une même tranche de comportement. Bloquez ou redirigez les auteurs directs qui contourneraient la nouvelle autorité. Ne gardez une façade de compatibilité que si les appelants ont besoin de temps, et faites-lui appeler le nouveau propriétaire au lieu d'héberger une seconde implémentation.

Le retour arrière doit préciser la direction des données, pas seulement celle du déploiement. Indiquez quel système reste l'autorité, quelles écritures s'arrêtent, comment les enregistrements propres à la cible reviennent dans Oracle si nécessaire et comment les effets déjà émis sont rapprochés. Le retour arrière d'un conteneur n'annule pas l'activité métier après que de l'argent, des messages ou des fichiers ont quitté la transaction.

L'arrêt d'Oracle constitue le test de réception

Une migration PL/SQL se termine lorsque l'entreprise peut fonctionner avec le comportement Oracle concerné désactivé et que l'équipe peut prouver la justesse des résultats. « Tous les corps de packages sont traduits » ne dit rien des triggers, tâches, variables globales de session, scripts d'exploitation ou appelants encore connectés directement.

Exigez pour chaque point d'entrée une chaîne fermée allant de l'acteur initiateur à une règle approuvée, un propriétaire cible, des cas de caractérisation réussis, un état de bascule et une observation en production. Rejouez l'inventaire du schéma et comparez-le à l'instantané initial. Chaque trigger encore actif, autorisation d'exécuter, tâche planifiée, synonyme et connexion applicative exige une raison explicite.

Effectuez ensuite un test de refus dans un environnement proche de la production. Révoquez l'ancien chemin d'exécution ou désactivez le trigger migré, lancez toute la suite de trafic et de cas conçus, puis surveillez les tentatives de connexion. Le test doit échouer si un chemin dépend encore d'Oracle. Un passage réussi prouve davantage qu'un tableau où chaque responsable a marqué sa ligne comme terminée.

Conservez l'instantané du source, le registre de comportements, les observations normalisées, les décisions et les résultats de parité comme un même dossier de preuves. Ils expliquent plus que le fonctionnement de l'ancien code. Ils montrent les bizarreries acceptées par l'entreprise, les défauts retirés et le nouvel emplacement de chaque règle survivante.

CodeHero livre les réécritures de systèmes anciens en moins de 30 jours, mais la vitesse n'autorise pas à deviner le comportement de la base. Pour aller vite, il faut inspecter tout le système ensemble, transformer les découvertes en comparaisons exécutables et refuser de déclarer une règle migrée tant qu'Oracle doit encore l'appliquer.

FAQ

Comment trouver tout le code PL/SQL d'une base Oracle ?

Interrogez DBA_SOURCE ou ALL_SOURCE pour les packages, corps, procédures, fonctions, triggers et types, puis extrayez leur DDL avec DBMS_METADATA. Ajoutez les tâches, autorisations, synonymes, objets invalides, colonnes virtuelles, index basés sur des fonctions et stratégies, car le texte source seul ne décrit pas chaque chemin d'appel.

ALL_DEPENDENCIES trouve-t-elle toutes les dépendances PL/SQL ?

Non. Elle enregistre les dépendances normales de compilation, mais le SQL dynamique, les noms configurés, synonymes, liens de base, résolutions avec les droits de l'appelant et appels externes peuvent échapper au graphe. Combinez-la avec des recherches dans le source et des traces d'exécution.

Faut-il sortir la logique métier des triggers de base ?

Déplacez les parcours et effets externes dans un service responsable, mais gardez les invariants universels à la frontière la plus étroite que tout auteur doit franchir. Une contrainte déclarative est généralement préférable à un trigger ou à des contrôles applicatifs dupliqués.

Comment tester un package PL/SQL avant sa réécriture ?

Appelez ses points d'entrée publics sur un jeu Oracle contrôlé et capturez retours, erreurs, changements de tables, événements et résultats transactionnels. Répétez les cas dans des sessions neuves, réutilisées, concurrentes et invalidées si le package conserve un état.

Pourquoi l'état des packages Oracle compte-t-il pendant une migration ?

Les variables de package peuvent persister pendant toute une session, si bien qu'un pool transporte un état caché entre les requêtes. Un remplacement sans état peut changer le comportement si les tests n'exposent pas cette dépendance et si les responsables ne décident pas de la garder ou de la retirer.

Le trafic de production suffit-il à prouver la parité PL/SQL ?

Non. Le rejeu fournit des entrées réalistes, mais manque les pannes rares, dates limites, appels non autorisés et branches jamais prises. Ajoutez des cas conçus depuis un registre de comportements et comparez les effets complets des transactions.

Comment migrer les transactions autonomes ?

Déterminez d'abord pourquoi l'ancien code valide ce travail indépendamment et si l'entreprise compte sur sa survie après une annulation. La plupart des cas d'audit ou de messagerie deviennent plus clairs avec une boîte d'envoi explicite ou une écriture séparément possédée, mais le comportement approuvé doit guider le choix.

Peut-on traduire directement Oracle PL/SQL vers PostgreSQL ?

La syntaxe peut être convertie, mais la traduction directe manque les différences d'état de package, de chaînes vides et valeurs nulles, d'erreurs, de privilèges, de transactions et de triggers. Récupérez d'abord le comportement, puis choisissez un propriétaire natif pour chaque règle.

Comment éviter les effets de trigger en double pendant la bascule ?

Tenez une matrice d'activation avec un seul exécuteur faisant autorité pour chaque règle du registre. Exécutez la nouvelle logique en mode fantôme sans mutation partagée, puis désactivez ou contournez l'ancien exécuteur dès que le nouveau chemin commence à écrire.

Quand une migration PL/SQL est-elle vraiment terminée ?

Elle est terminée lorsque les chemins Oracle migrés peuvent être désactivés et que le rejeu du trafic ainsi que les cas conçus réussissent encore. Chaque trigger, tâche, autorisation, synonyme et connexion directe restante doit avoir un propriétaire et une raison explicites.