Les projets de migration de bases Oracle vers PostgreSQL fleurissant pas mal ces derniers temps, cet article vise à présenter l’outil de migration Ora2Pg sur un cas simple et concret de migration, celui du schéma de démonstration HR.
Pour pouvoir utiliser l’outil Ora2Pg, il vous faut tout d’abord disposer d’un moteur et d’une instance PostgreSQL dans laquelle nous créerons la base dans laquelle le schéma HR cible sera hébergé.
L’outil Ora2Pg s’installe en suivant les quelques étapes mentionnées ci-dessous :
paquets RPM
yum install gcc bzip2 perl-devel unzip yum install perl-Time-HiRes (si RHEL 6.x)
Installation d’un client Oracle
Le choix de l’instant client 12.2 est proposé dans cet article, pour sa simplicité d’installation et son coté non intrusif.
Il dispose, de plus, dans sa dernière version, des outils datapump (export / import), SQL*Loader et du WRC (Workload Replay Client) pour rejouer une charge de production sur une base de tests.
Les fichiers de l’instant client 12.2 sont téléchargeables sur le lien: http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html
unzip /tmp/instantclient-basic-linux.x64-12.2.0.1.0.zip -d /opt/oracle unzip /tmp/instantclient-sdk-linux.x64-12.2.0.1.0.zip -d /opt/oracle unzip /tmp/instantclient-sqlplus-linux.x64-12.2.0.1.0.zip -d /opt/oracle
Configuration du TNSNAMES.ORA
vi /opt/oracle/instantclient_12_2/tnsnames.ora BASETEST= (DESCRIPTION = (ADDRESS=(PROTOCOL=TCP)(HOST=<mon serveur>)(PORT=1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = pdb1) ) )
Installation du module DBI
à télécharger sur le site https://metacpan.org/release/DBI et prendre une version supérieure à 1.614.
export ORACLE_HOME=/opt/oracle/instantclient_12_2 export TNS_ADMIN=/opt/oracle/instantclient_12_2 export PATH=$ORACLE_HOME:$PATH export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH tar -zxf DBI-1.636.tar.gz cd DBI-1.636 perl Makefile.PL make && make install
Installation du module DBD::Oracle
à télécharger sur le site search.cpan.org/dist/DBD-Oracle
export ORACLE_HOME=/opt/oracle/instantclient_12_2 export TNS_ADMIN=/opt/oracle/instantclient_12_2 export PATH=$ORACLE_HOME:$PATH export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH tar -zxf DBD-Oracle-1.74.tar.gz cd DBD-Oracle-1.74 perl Makefile.PL make && make install
Installation de l’outil Ora2Pg
à télécharger sur le site https://sourceforge.net/projects/ora2pg
export ORACLE_HOME=/opt/oracle/instantclient_12_2 export TNS_ADMIN=/opt/oracle/instantclient_12_2 export PATH=$ORACLE_HOME:$PATH export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH cd /tmp tar -jxf ora2pg-18.1.tar.bz2 cd ora2pg-18.1 perl Makefile.PL make && make install chown -R postgres:postgres /etc/ora2pg
L’outil est maintenant installé dans /usr/local/bin et n’attend plus qu’à être paramétré pour pouvoir l’utiliser.
Configuration d’Ora2Pg
Le fichier de paramètres utilisé par défaut par Ora2Pg se nomme /etc/ora2pg/ora2pg.conf.dist, mais peut être écrasé par tout autre nom en utilisant l’option –conf <nom du fichier de paramètres> de l’outil Ora2Pg.
Dans notre exemple, nous créerons à partir d’une copie de /etc/ora2Pg/ora2pg.conf.dist un fichier /etc/ora2pg/ora2pg.conf.HR contenant les quelques modifications qui suivent et qui suffisent à une grande majorité des situations de migration.
cp /etc/ora2pg/ora2pg.conf.dist /etc/ora2pg/ora2pg.conf.HR vi /etc/ora2pg/ora2pg.conf.HR # fournir le chemin d'accès au client Oracle (pour nous, l'instant client 12.2) ORACLE_HOME /opt/oracle/instantclient_12_2 # fournir les éléments de connexion à la base Oracle ORACLE_DSN dbi:Oracle:BASETEST ORACLE_USER system ORACLE_PWD <mot de passe> # Le schéma à migrer SCHEMA HR Si SCHEMA n'est pas renseigné, Ora2Pg cherchera à migrer tous les schémas de la base à l'exception de ceux fournis par Oracle (SYS, SYSTEM, SYSMAN, etc...) # Certaines applications utilisent des mots-clés réservés (ex: FROM) comme noms de tables. USE_RESERVED_WORLDS = 1 (pour permettre l'utilisation de noms d'objets utilisant des mots-clés réservés (ex: from, user, etc...))
Initialisation d’Ora2Pg
Maintenant que notre projet de migration est défini, nous allons initialiser l’arborescence qui lui servira de zone de travail, et qui contiendra les données à migrer en exécutant la commande qui suit, après vous être assuré de disposer de suffisamment de place disques dans ce répertoire.
export ORACLE_HOME=/opt/oracle/instantclient_12_2 export TNS_ADMIN=/opt/oracle/instantclient_12_2 export PATH=$ORACLE_HOME:$PATH export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH ora2pg --project_base <répertoire racine> --init_project HR --conf /etc/ora2pg/ora2pg.conf.HR Creating project HR. <répertoire racine>/HR/ schema/ dblinks/ directories/ functions/ grants/ mviews/ packages/ partitions/ procedures/ sequences/ synonyms/ tables/ tablespaces/ triggers/ types/ views/ sources/ functions/ mviews/ packages/ partitions/ procedures/ triggers/ types/ views/ data/ config/ reports/ Generating generic configuration file Creating script export_schema.sh to automate all exports. Creating script import_all.sh to automate all imports.
Evaluation des difficultés de migration
Tout est prêt pour démarrer cette migration, mais avant même de nous lancer dans cet exercice, j’aimerais vous montrer la capacité d’Ora2Pg à évaluer le niveau de difficultés que vous risquez de rencontrer.
export ORACLE_HOME=/opt/oracle/instantclient_12_2 export TNS_ADMIN=/opt/oracle/instantclient_12_2 export PATH=$ORACLE_HOME:$PATH export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH ora2pg -t SHOW_REPORT --estimate_cost --conf /etc/ora2pg/ora2pg.conf.HR [========================>] 7/7 tables (100.0%) end of scanning. [========================>] 9/9 objects types (100.0%) end of objects auditing.
L’ajout des options –dump_as_html ou –dump_as_csv à la commande ora2pg permettent la sortie des résultats sous forme de page HTML ou de fichier type EXCEL.
Cette commande fournit le détail des objets à migrer, et surtout un niveau global de difficulté sous la forme d’un code constitué d’une lettre (A,B ou C) et d’un nombre de 1 à 5.
Bien sûr, ce code reste une approximation mais donne tout de même une idée des efforts à fournir pour assurer cette migration.
Notre exemple est d’un niveau A-3, donc relativement simple, ce que vous pourrez d’ailleurs constater par vous-même dans cet article.
Export des données
Passons maintenant à la phase d’export des données à migrer en exécutant le script export_schema.sh généré précédemment lors de l’initialisation du projet.
$ ./export_schema.sh [========================>] 7/7 tables (100.0%) end of scanning. [========================>] 9/9 objects types (100.0%) end of objects auditing. Running: ora2pg -p -t TABLE -o table.sql -b ./schema/tables -c ./config/ora2pg.conf [========================>] 7/7 tables (100.0%) end of scanning. [========================>] 7/7 tables (100.0%) end of table export. Running: ora2pg -p -t PACKAGE -o package.sql -b ./schema/packages -c ./config/ora2pg.conf [========================>] 0/0 packages (100.0%) end of output. Running: ora2pg -p -t VIEW -o view.sql -b ./schema/views -c ./config/ora2pg.conf [========================>] 1/1 views (100.0%) end of output. Running: ora2pg -p -t GRANT -o grant.sql -b ./schema/grants -c ./config/ora2pg.conf Running: ora2pg -p -t SEQUENCE -o sequence.sql -b ./schema/sequences -c ./config/ora2pg.conf [========================>] 3/3 sequences (100.0%) end of output. Running: ora2pg -p -t TRIGGER -o trigger.sql -b ./schema/triggers -c ./config/ora2pg.conf [========================>] 1/1 triggers (100.0%) end of output. Running: ora2pg -p -t FUNCTION -o function.sql -b ./schema/functions -c ./config/ora2pg.conf [========================>] 0/0 functions (100.0%) end of output. Running: ora2pg -p -t PROCEDURE -o procedure.sql -b ./schema/procedures -c ./config/ora2pg.conf [========================>] 2/2 procedures (100.0%) end of output. Running: ora2pg -p -t TABLESPACE -o tablespace.sql -b ./schema/tablespaces -c ./config/ora2pg.conf Running: ora2pg -p -t PARTITION -o partition.sql -b ./schema/partitions -c ./config/ora2pg.conf [========================>] 0/0 partitions (100.0%) end of output. Running: ora2pg -p -t TYPE -o type.sql -b ./schema/types -c ./config/ora2pg.conf [========================>] 0/0 types (100.0%) end of output. Running: ora2pg -p -t MVIEW -o mview.sql -b ./schema/mviews -c ./config/ora2pg.conf [========================>] 0/0 materialized views (100.0%) end of output. Running: ora2pg -p -t DBLINK -o dblink.sql -b ./schema/dblinks -c ./config/ora2pg.conf [========================>] 0/0 dblink (100.0%) end of output. Running: ora2pg -p -t SYNONYM -o synonym.sql -b ./schema/synonyms -c ./config/ora2pg.conf [========================>] 0/0 synonyms (100.0%) end of output. Running: ora2pg -p -t DIRECTORY -o directorie.sql -b ./schema/directories -c ./config/ora2pg.conf [========================>] 0/0 directory (100.0%) end of output. Running: ora2pg -t PACKAGE -o package.sql -b ./sources/packages -c ./config/ora2pg.conf [========================>] 0/0 packages (100.0%) end of output. Running: ora2pg -t VIEW -o view.sql -b ./sources/views -c ./config/ora2pg.conf [========================>] 1/1 views (100.0%) end of output. Running: ora2pg -t TRIGGER -o trigger.sql -b ./sources/triggers -c ./config/ora2pg.conf [========================>] 1/1 triggers (100.0%) end of output. Running: ora2pg -t FUNCTION -o function.sql -b ./sources/functions -c ./config/ora2pg.conf [========================>] 0/0 functions (100.0%) end of output. Running: ora2pg -t PROCEDURE -o procedure.sql -b ./sources/procedures -c ./config/ora2pg.conf [========================>] 2/2 procedures (100.0%) end of output. Running: ora2pg -t PARTITION -o partition.sql -b ./sources/partitions -c ./config/ora2pg.conf [========================>] 0/0 partitions (100.0%) end of output. Running: ora2pg -t TYPE -o type.sql -b ./sources/types -c ./config/ora2pg.conf [========================>] 0/0 types (100.0%) end of output. Running: ora2pg -t MVIEW -o mview.sql -b ./sources/mviews -c ./config/ora2pg.conf [========================>] 0/0 materialized views (100.0%) end of output. To extract data use the following command: ora2pg -t COPY -o data.sql -b ./data -c ./config/ora2pg.conf
Pour effectuer cet export, et pour de grosses volumétries, on peut utiliser l’option de parallélisation comme ci-dessous pour paralléliser cet export sur 4 canaux :
$ ora2pg -t COPY -o data.sql -b ./data -c ./config/ora2pg.conf --parallel 4 [========================>] 7/7 tables (100.0%) end of scanning. [========================>] 25/25 rows (100.0%) Table COUNTRIES (0 sec., 25 recs/sec) [========================>] 27/27 rows (100.0%) Table DEPARTMENTS (0 sec., 27 recs/sec) [========================>] 107/107 rows (100.0%) Table EMPLOYEES (0 sec., 107 recs/sec) [========================>] 19/19 rows (100.0%) Table JOBS (0 sec., 19 recs/sec) [========================>] 10/10 rows (100.0%) Table JOB_HISTORY (0 sec., 10 recs/sec) [========================>] 23/23 rows (100.0%) Table LOCATIONS (0 sec., 23 recs/sec) [========================>] 4/4 rows (100.0%) Table REGIONS (0 sec., 4 recs/sec) [========================>] 215/215 rows (100.0%) on total estimated data (5 sec., avg: 43 tuples/sec)
Contrôle des scripts générés
Allons maintenant examiner les scripts générés, et nous assurer que les contraintes référentielles seront correctement gérées lors de l’étape d’import, car il arrive, en fonction des versions de composants installés, que ce ne soit pas toujours le cas.
Pour cela, il suffit de vérifier dans le sous-répertoire schema/tables l’existence des scripts CONSTRAINTS_table.sql et INDEXES_table.sql.
Si ces deux scripts n’ont pas été générés, voici comment procéder :
$ cd schema/tables $ ls table.sql $ mv table.sql table.sav $ cat table.sav | grep -v "^ALTER" | grep -v INDEX > table.sql $ cat table.sav | grep INDEX > INDEXES_table.sql $ cat table.sav | grep "^ALTER" > CONSTRAINTS_table.sql
Import des données (dans la base PostgreSQL)
Passons maintenant à l’étape d’import.
Nous allons importer notre schéma HR dans une base postgreSQL nommée sample, dans laquelle nous allons créer un schéma et un utilisateur HR (sous PostgreSQL, le schéma et l’utilisateur sont deux entités indépendantes alors qu’elles ne sont qu’une sous Oracle).
Dans ce qui suit, nous répondrons oui à l’ensemble des questions à l’exception de celles traitant des indexes et contraintes avant l’import, ainsi que les procédures et triggers qui seront traitées après l’import pour éviter les plantages dus aux contraintes d’intégrités et aux différences de codes entre PL/SQL et PGPLSQL.
$ ./import_all.sh -d sample -o hr -n hr Would you like to create the owner of the database hr? [y/N/q] y Would you like to create the database sample? [y/N/q] y Running: createdb -E UTF8 --owner hr sample Would you like to create schema hr in database sample? [y/N/q] y CREATE SCHEMA Would you like to change search_path of the database owner? [y/N/q] y Running: psql -d sample -c "ALTER ROLE hr SET search_path TO hr,public;" ALTER ROLE Would you like to import TABLE from ./schema/tables/table.sql? [y/N/q] y SET CREATE TABLE COMMENT COMMENT ... COMMENT CREATE TABLE Would you like to import VIEW from ./schema/views/view.sql? [y/N/q] y Running: psql --single-transaction -U hr -d sample -f ./schema/views/view.sql SET CREATE VIEW Would you like to import SEQUENCE from ./schema/sequences/sequence.sql? [y/N/q] y Running: psql --single-transaction -U hr -d sample -f ./schema/sequences/sequence.sql SET CREATE SEQUENCE CREATE SEQUENCE CREATE SEQUENCE Would you like to import TRIGGER from ./schema/triggers/trigger.sql? [y/N/q] n Would you like to import PROCEDURE from ./schema/procedures/procedure.sql? [y/N/q] n Would you like to process indexes and constraints before loading data? [y/N/q] n Would you like to import TABLESPACE from ./schema/tablespaces/tablespace.sql? [y/N/q] n Would you like to import data from ./data/data.sql? [y/N/q] y Running: psql -U hr -d sample -f ./data/data.sql SET BEGIN COPY 25 COPY 27 COPY 107 COPY 19 COPY 10 COPY 23 COPY 4 ALTER SEQUENCE ALTER SEQUENCE ALTER SEQUENCE COMMIT Would you like to import indexes from ./schema/tables/INDEXES_table.sql? [y/N/q] y Running: psql -U hr -d sample -f ./schema/tables/INDEXES_table.sql CREATE INDEX CREATE INDEX ... CREATE INDEX Would you like to import constraints from ./schema/tables/CONSTRAINTS_table.sql? [y/N/q] y Running: psql -U hr -d sample -f ./schema/tables/CONSTRAINTS_table.sql ALTER TABLE ALTER TABLE ... ALTER TABLE ALTER TABLE Si vous etes en version 18.2 d'Ora2Pg : Would you like to import foreign keys from ./schema/tables/FKEYS_table.sql? [y/N/q] n
Ce dernier script (FKEYS_tables.sql) qui apparait en version 18.2 d’Ora2Pg, peut parfois se planter, en particulier si les tables concernées sont munies de l’attribut UNLOGGED (l’équivalent de l’option NOLOGGING sous Oracle), c’est pourquoi il vaut mieux l’exécuter manuellement.
cd schema/tables psql -d sample -U hr -f FKEYS_table.sql SET psql:FKEYS_table.sql:9: ERROR: constraints on permanent tables may reference only permanent tables La ligne 9 contient l'ordre suivant : ALTER TABLE countries ADD CONSTRAINT countr_reg_fk FOREIGN KEY (region_id) REFERENCES regions(region_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE;
Justement, ça plante dans notre cas, nous allons donc retirer l’attribut UNLOGGED des tables concernées avant de repasser ce script :
psql -d sample -U hr sample=> alter table countries set logged ; sample=> alter table regions set logged ; sample=> sample=> \i FKEYS_tables.sql SET ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE
Çà y est, c’est passé !
Il ne nous reste plus qu’à achever l’exercice en créant cette fois les procédures, fonctions et triggers, bref, tout ce qui inclut des ordres de type PL/SQL pour tenter de les adapter au langage PGPLSQL, ce qui parfois peut s’avérer long et fastidieux.
C’est d’ailleurs la plus grosse difficulté rencontrée lors d’une migration d’Oracle vers PostgreSQL.
Pour les procédures :
psql -d sample -U hr -f schema/procedures/procedure.sql SET psql:procedure.sql:20: NOTICE: référence de type job_history.employee_id%TYPE convertie en integer psql:procedure.sql:20: NOTICE: référence de type job_history.start_date%TYPE convertie en timestamp without time zone psql:procedure.sql:20: NOTICE: référence de type job_history.end_date%TYPE convertie en timestamp without time zone psql:procedure.sql:20: NOTICE: référence de type job_history.job_id%TYPE convertie en character varying psql:procedure.sql:20: NOTICE: référence de type job_history.department_id%TYPE convertie en smallint CREATE FUNCTION CREATE FUNCTION
Juste un WARNING signalant la conversion des variables de type table.colonne%TYPE par le type de la colonne, je décide donc dans cet article de passer à la suite en créant les triggers.
Pour les triggers :
psql -d sample -U hr -f schema/triggers/trigger.sql SET psql:trigger.sql:9: NOTICE: le trigger « update_job_history » de la relation « employees » n'existe pas, poursuite du traitement DROP TRIGGER psql:trigger.sql:17: ERREUR: erreur de syntaxe sur ou près de « add_job_history » LINE 3: add_job_history(OLD.employee_id, OLD.hire_date, LOCALTIMES...
Cette fois, j’ai moins de chance et mon trigger n’a pas été migré.
En version 18.2, Ora2Pg ajoute lui-même la bonne clause et le trigger est correctement créé.
En 18.1, voici ce qu’il faut faire.
Ci-dessous le code de définition de ce trigger :
-- Generated by Ora2Pg, the Oracle database Schema converter, version 18.1 -- Copyright 2000-2017 Gilles DAROLD. All rights reserved. -- DATASOURCE: dbi:Oracle:BASETEST SET client_encoding TO 'UTF8'; \set ON_ERROR_STOP ON DROP TRIGGER IF EXISTS update_job_history ON employees CASCADE; CREATE OR REPLACE FUNCTION trigger_fct_update_job_history() RETURNS trigger AS $BODY$ BEGIN add_job_history(OLD.employee_id, OLD.hire_date, LOCALTIMESTAMP, OLD.job_id, OLD.department_id); RETURN NEW; END $BODY$ LANGUAGE 'plpgsql' SECURITY DEFINER; -- REVOKE ALL ON FUNCTION trigger_fct_update_job_history() FROM PUBLIC; CREATE TRIGGER update_job_history AFTER UPDATE ON employees FOR EACH ROW EXECUTE PROCEDURE trigger_fct_update_job_history();
Ce trigger se déclenche sur un UPDATE réalisé sur la table EMPLOYEES et enregistre ce changement dans la table JOB_HISTORY mais l’appel à ce trigger sous PostgreSQL doit se faire via une commande SELECT <nom de la fonction> ou PERFORM <nom de la fonction>, ce qui n’est pas le cas sous Oracle.
Nous allons donc modifier le script SQL trigger trigger.sql pour y ajouter un PERFORM avant de relancer l’exécution du script.
SET psql:trigger.sql:9: NOTICE: le trigger « update_job_history » de la relation « employees » n'existe pas, poursuite du traitement DROP TRIGGER CREATE FUNCTION CREATE TRIGGER
Cette fois-ci, ça passe !
Testons maintenant ce trigger pour vérifier qu’il fonctionne correctement, en modifiant une entrée de la table EMPLOYEES, ce qui déclenchera le trigger en question.
psql -d sample -U hr sample=> select * from employees where employee_id = 101; employee_id | first_name | last_name | email | phone_number | hire_date | job_id | salary | commission_pct | manager_id | department_id -------------+------------+-----------+----------+--------------+---------------------+--------+--------+----------------+------------+--------------- 101 | Neena | Kochhar | NKOCHHAR | 515.123.4568 | 2005-09-21 00:00:00 | AD_VP | 17000 | | 100 | 90 (1 row) sample=> update employees set job_id = 'AC_MGR' where employee_id = 101 ; UPDATE 1 sample=> select * from employees where employee_id = 101; employee_id | first_name | last_name | email | phone_number | hire_date | job_id | salary | commission_pct | manager_id | department_id -------------+------------+-----------+----------+--------------+---------------------+--------+--------+----------------+------------+--------------- 101 | Neena | Kochhar | NKOCHHAR | 515.123.4568 | 2005-09-21 00:00:00 | AC_MGR | 17000 | | 100 | 90 (1 row) sample=> select * from job_history ; employee_id | start_date | end_date | job_id | department_id -------------+---------------------+---------------------------+------------+--------------- 102 | 2001-01-13 00:00:00 | 2006-07-24 00:00:00 | IT_PROG | 60 101 | 1997-09-21 00:00:00 | 2001-10-27 00:00:00 | AC_ACCOUNT | 110 101 | 2001-10-28 00:00:00 | 2005-03-15 00:00:00 | AC_MGR | 110 201 | 2004-02-17 00:00:00 | 2007-12-19 00:00:00 | MK_REP | 20 114 | 2006-03-24 00:00:00 | 2007-12-31 00:00:00 | ST_CLERK | 50 122 | 2007-01-01 00:00:00 | 2007-12-31 00:00:00 | ST_CLERK | 50 200 | 1995-09-17 00:00:00 | 2001-06-17 00:00:00 | AD_ASST | 90 176 | 2006-03-24 00:00:00 | 2006-12-31 00:00:00 | SA_REP | 80 176 | 2007-01-01 00:00:00 | 2007-12-31 00:00:00 | SA_MAN | 80 200 | 2002-07-01 00:00:00 | 2006-12-31 00:00:00 | AC_ACCOUNT | 90 101 | 2005-09-21 00:00:00 | 2017-08-02 12:12:53.49093 | AD_VP | 90 (11 rows)
Vous remarquerez dans la dernière ligne de la table job_history le format du champs « end_date » qui diffère des autres.
Ce qui montre bien à la fois la relative simplicité de migration d’un schéma Oracle vers une base PostgreSQL, mais aussi que les plus grosses difficultés à gérer se trouvent, d’une part dans le portage des objets utilisant le code PL/SQL, et d’autre part sur le temps à consacrer aux tests du comportement de votre application après migration pour vous assurer de l’identité parfaite avant et après. (ex: le format du champ end_date)
Pour les perfectionnistes qui aimeraient aller jusqu’au bout de cette première expérience de migration et connaitre la solution à ce problème de format de champ end_date, en voici une :
Remplacer le code du trigger (trigger.sql)
PERFORM add_job_history(OLD.employee_id, OLD.hire_date, LOCALTIMESTAMP,
OLD.job_id, OLD.department_id);
Par celui-ci
PERFORM add_job_history(OLD.employee_id, OLD.hire_date, date_trunc(‘second’,LOCALTIMESTAMP),
OLD.job_id, OLD.department_id);
Bonne(s) migration(s) !
1 réflexion sur “Initiation à Ora2Pg”
Bravo ! merci ,
dans les nouvelles versions d’Ora2pg le problème de trigger est résolue .
– Generated by Ora2Pg, the Oracle database Schema converter, version 21.1
— Copyright 2000-2020 Gilles DAROLD. All rights reserved.
— DATASOURCE: dbi:Oracle:mydbfortest
SET client_encoding TO ‘UTF8’;
\set ON_ERROR_STOP ON
SET check_function_bodies = false;
DROP TRIGGER IF EXISTS update_job_history ON employees CASCADE;
CREATE OR REPLACE FUNCTION trigger_fct_update_job_history() RETURNS trigger AS $BODY$
BEGIN
PERFORM add_job_history(OLD.employee_id, OLD.hire_date, LOCALTIMESTAMP,
OLD.job_id, OLD.department_id);
RETURN NEW;
END
$BODY$
LANGUAGE ‘plpgsql’ SECURITY DEFINER;
— REVOKE ALL ON FUNCTION trigger_fct_update_job_history() FROM PUBLIC;
CREATE TRIGGER update_job_history
AFTER UPDATE OF job_id,department_id ON employees FOR EACH ROW
EXECUTE PROCEDURE trigger_fct_update_job_history();
Par contre dans l’article il manque des précisions : lors de l’import il faut donner le droit à l’utilisateur postgres pour exécuter import_all.sh
aussi pour LD_LIBRARY_PATH = $ORACLE_HOME/lib
Le reste c’est nickel !
Encore Bravo !
Les commentaires sont fermés.