Procédures stockées

Module N4

Dalibo SCOP

24.09

29 août 2024

Sur ce document

Formation Module N4
Titre Procédures stockées
Révision 24.09
PDF https://dali.bo/n4_pdf
EPUB https://dali.bo/n4_epub
HTML https://dali.bo/n4_html
Slides https://dali.bo/n4_slides
TP https://dali.bo/n4_tp
TP (solutions) https://dali.bo/n4_solutions

Licence Creative Commons CC-BY-NC-SA

Cette formation est sous licence CC-BY-NC-SA. Vous êtes libre de la redistribuer et/ou modifier aux conditions suivantes :

  • Paternité
  • Pas d’utilisation commerciale
  • Partage des conditions initiales à l’identique

Marques déposées

PostgreSQL® Postgres® et le logo Slonik sont des marques déposées par PostgreSQL Community Association of Canada.

Versions de PostgreSQL couvertes

Ce document ne couvre que les versions supportées de PostgreSQL au moment de sa rédaction, soit les versions 12 à 16.

Procédures stockées

Introduction

Oracle et PostgreSQL n’ont pas le même langage PL :

  • Oracle : PL/SQL et Java
  • PostgreSQL : PL/pgSQL, PL/Java, PL/Perl, PL/Python, PL/R…

Sommaire

Ce module est organisé en cinq parties :

  • Outils et méthodes
  • Différences dans le code
  • Conversion automatique
  • Migration des procédures stockées
  • Tests et validation

Outils et méthodes

  • Outils d’émulation de fonctionnalités Oracle
  • Outils de conversion de code PL/SQL vers PL/pgSQL
  • Outils de débogage du code PL/pgSQL

Les outils d’émulation

  • Orafce :
    • nombreuses fonctions de compatibilité Oracle
    • to_char(1 param), add_month(), decode()
    • DBMS_ALERT, DBMS_PIPE, DBMS_OUTPUT, DBMS_RANDOM et UTL_FILE
  • Migration Tool Kit :
    • réservé à EDB PostgreSQL Plus Advanced Server Migration
    • ne convertit pas le code PL/SQL

Les outils de conversion

  • Ora2pg
    • convertisseur de code PL/SQL en PL/pgSQL sous licence GPL
    • seul outil libre

Les outils de débogage

  • pldebugger (ex edb-debugger)
  • plpgsql_check
  • SQLMaestro

Différences dans le code

  • Généralité
  • Triggers
  • Routines
  • Packages

Généralité - 1

  • nom_sequence.nextval => nextval('nom_sequence')
  • Pas de transaction autonome à moins de passer par dblink ou pg_background
  • RETURN => RETURNS
  • EXECUTE IMMEDIATE => EXECUTE
  • SELECT sans INTO => PERFORM

Généralité - 2

  • REVERSE LOOP => inversion des bornes
  • Une fonction doit avoir un langage
  • CONNECT BY n’existe pas, utiliser WITH RECURSIVE
  • REF CURSOR doit être remplacé par REFCURSOR
  • nom_curseur%ROWTYPE doit être remplacé par RECORD
  • BULK COLLECT => Array
  • Les chaînes vides sont équivalentes à NULL sous Oracle

Triggers

  • Ils doivent être séparés en fonction et trigger
  • :NEW et :OLD => NEW et OLD
  • UPDATING, INSERTING, DELETING => TG_OP (UPDATE, INSERT, DELETE)
  • RETURN NEW impératif dans les triggers BEFORE, retour implicite sous Oracle

Routines

  • PostgreSQL supporte les fonctions et procédures stockées
    • uniquement les fonctions pour les versions 10 ou inférieures
  • Il doit toujours y voir des parenthèses pour la liste des paramètres, même si elle est vide
  • Les valeurs par défaut sont aussi autorisées
  • PostgreSQL peut retourner un pseudo type RECORD, correspondant à un enregistrement
    • sous Oracle, il faut soit utiliser une référence de curseur soit définir une TABLE FUNCTION

Packages

  • Paquet de variables et de procédures stockées
    • pas d’équivalent sous PostgreSQL
  • Utilisation d’un schéma pour émuler les appels aux fonctions
    • nom_paquet.nom_fonction
  • Variables globales non supportées
    • utiliser des tables ou des paramètres de configuration (GUC)
  • Les définitions de fonctions à l’intérieur du code d’une fonction ne sont pas supportées

Conversion automatique du code

  • Paquets de procédure stockées
  • En-têtes et paramètres des triggers, fonctions etc.
  • Types des données
  • Fonctions
  • Modification de syntaxe

Conversions globales

  • Les PACKAGES ou paquets de procédures stockées
  • Les déclarations de triggers et routines
  • Les paramètres des routines
  • La conversion des types de variable

Correspondance des fonctions - 1

Les noms diffèrent :

  • NVL() => coalesce()
  • SYSDATE => LOCALTIMESTAMP
    • équivalent de CURRENT_TIMESTAMP sans le fuseau horaire
  • NLSSORT(colname, 'nls_sort=GERMAN') => colname COLLATE "de_DE"

Correspondance des fonctions - 2

Les paramètres changent :

  • to_number(num)
    • => to_number(num, '99...99D99...99')
  • to_date( string1, format_mask, nls_language)
    • => to_date(text, text)
  • replace(a, b)
    • => replace(a, b, ' ')

Correspondance des fonctions - 3

Les noms et les paramètres changent :

trunc(.*date.*)
 => date_trunc('day', ...date...)
substr( string, start_position, length )
 => substring(string from start_position for length)

Correspondance des fonctions - 4

La réécriture est complète :

add_months
 =>+ 'N months'::interval
add_years
 =>+ 'N year'::interval
TO_NUMBER(TO_CHAR(…))
 => to_char(…)::integer
decode("user_status",'active',"username",null)
 => (CASE WHEN user_status='active' THEN username ELSE NULL END)

Réécriture de parties de code - 1

  • Réécrit les appels aux séquences
    • nom.nextval => nextval('nom')
    • nom.currval => currval('nom')
  • Remplace les appels :new. en NEW. et :old. en OLD. dans les triggers
  • Remplace INSERTING|DELETING|UPDATING en TG_OP='INSERT|DELETE|UPDATE' dans les fonctions de trigger

Réécriture de parties de code - 2

  • Supprime le caractère : devant les noms de variable Oracle
  • Convertit les sorties Oracle DBMS_OUTPUT.(put_line|put|new_line)(...) en RAISE NOTICE '...'
  • Inversement des bornes min et max dans les boucles FOR … IN … REVERSE min .. max
  • Réécrit les RAISE EXCEPTIONavec concaténation || par le format à la sprintf utilisé par PostgreSQL

Réécriture de parties de code - 3

  • Remplacement des ROWNUM dans la clause where par des clauses LIMIT et/ou OFFSET
  • Réécrit la clause HAVING … GROUP BY (variante acceptée par Oracle mais pas PostgreSQL) en GROUP BY … HAVING
  • Remplace les appels à MINUS par EXCEPT

Réécriture de parties de code - 4

  • Supprime les appels à FROM DUAL
  • Supprime les DEFAULT NULL qui est la valeur par défaut sous PostgreSQL lorsqu’aucune valeur par défaut n’est précisée
  • Suppression des noms d’objets répétés après les END, exemple : END fct_name; est réécrit en END;

Réécriture de parties de code - 5

  • Déplacement des commentaires dans les CASE entre le WHEN et le THEN, non supporté par PostgreSQL
  • Remplacement des conditions IS NULL et IS NOT NULL par des instructions à base de coalesce (pour Oracle, une chaîne vide est équivalente à NULL)
  • Inverse les déclarations de curseur CURSOR moncurseur; pour les rendre compatibles avec PostgreSQL : moncurseur CURSOR;

Réécriture de parties de code - 6

  • Supprime le mot clé IN de la déclaration des curseurs.
  • Remplacement des sorties de curseur EXIT WHEN ...%NOTFOUND par IF NOT FOUND THEN EXIT; END IF;
  • Ajout du mot clé STRICT aux SELECT … INTO lorsqu’il y a EXCEPTION … NO_DATA_FOUND ou TOO_MANY_ROWS

Réécriture de parties de code - 7

  • Remplacement des REGEX_LIKE( string, pattern ) en syntaxe avec l’opérateur PostgreSQL de recherche regex string ~ pattern.
  • Remplacement des appels aux variables d’environnement SYS_CONTECT('USERENV', ...) en équivalent PostgreSQL.
  • Remplacement des fonctions spatiales SDO_GEOM.* en appels aux fonctions PostGis équivalentes.
  • Remplacement des opérateurs géométriques SDO_* en opérateurs correspondants PostGis.

Remplacement concernant les exceptions

Remplacement de :

  • STORAGE_ERROR par OUT_OF_MEMORY
  • ZERO_DIVIDE par DIVISION_BY_ZERO
  • INVALID_CURSOR par INVALID_CURSOR_STATE
  • SQLCODE par le presque équivalent SQLSTATE sous PostgreSQL
  • raise_application_error en RAISE EXCEPTION

Remplacement d’autres mots clés

Remplacement de :

  • SYS_REFCURSOR par REFCURSOR
  • SQL%NOTFOUND par NOT FOUND
  • SYS_EXTRACT_UTC par AT TIME ZONE 'UTC
  • dup_val_on_index en unique_violation

Migration des procédures stockées

Étapes :

  • Cas des procédures avec transactions autonomes
  • Import des fonctions et paquets de fonctions
  • Absence de fonctions ou paquets

Cas des transactions autonomes

Non supportées nativement par PostgreSQL, Ora2Pg utilise une fonction de substitution :

  • La fonction d’origine est renommée avec le suffixe _atx
  • La fonction de substitution prend le nom originel de la fonction
  • La fonction de substitution appelle la fonction _atx au travers d’un dblink
  • Utilisation possible de l’extension pg_background à partir de PostgreSQL 9.5 et Ora2Pg 17.5

Import des procédures et paquets avec Ora2Pg

Chargement des fonctions et procédures :

psql --single-transaction -U myuser -f schema/functions/functions.sql mydb
psql --single-transaction -U myuser -f schema/procedures/procedures.sql mydb

Chargement des paquets de procédures stockées :

psql --single-transaction -U myuser -f schema/packages/packages.sql mydb

Code non exporté

Absence de certaines fonctions ou paquets de fonctions dans l’export

  • Le code a été invalidé par Oracle
  • Activer COMPILE_SCHEMA
  • Activer EXPORT_INVALID

Certains commentaires des paquets de fonctions ne sont pas importés

Tests et validation

Valider le portage du code :

  • Fonctionnement à l’identique
  • Possibilité de résultats différents
  • Déboguer le code PL/pgSQL et comparer avec le code source
  • Ne pas oublier le test des scripts ou jobs externes

Ora2Pg : tests intégrés

Deux actions permettent de tester à minima :

  • TEST : compare le nombre d’objets et de lignes des deux bases.
    • ora2pg -c config/ora2pg.conf -t TEST
  • TEST_VIEW : compare le nombre de lignes retounées par les vues.
    • ora2pg -c config/ora2pg.conf -t TEST_VIEW
  • Dans les deux cas PG_DSN doit être positionné.

Outils de tests unitaires pour PostgreSQL

Plans de tests complets

  • Tests sur la base de données
  • Tests sur l’application
  • Tests sur les performances
  • Stress test
  • Tests des scripts de maintenance et job

Conclusion

  • La conversion automatique fait gagner du temps
  • Mais les réécritures manuelles peuvent s’avérer nombreuses
  • La phase de tests est la plus importante de la migration

Questions

N’hésitez pas, c’est le moment !

Quiz

Travaux pratiques

Travaux pratiques (solutions)