Reverse Engineering Oracle 10g pour les imports

Logo

Introduction

Cet article propose les requêtes indispensables pour préparer les comptes, rôles, privilèges, etc. dans une instance Oracle qui va être chargée à partir d’un export. Dans cet exemple, les instances source et cible sont appelées respectivement INSTANCE1 (Oracle 10g) et INSTANCE2 (Oracle 10g). La procédure d’export/import a été réalisée dans le cadre d’une migration de plateforme de Sun Solaris SPARC vers Sun Solaris X86 (AMD), la méthode des tablespaces transportables (transportable tablespaces ou TTS) n’a pas pu être appliquée car des tables et indexes partitionnés en mode IOT (Index Organized Tables) sont présents dans les schémas et ces fonctionnalités de partitionnement ne sont pas supportées dans la technologie TTS 10g.

Si les profils, comptes, rôles, synonymes publics, etc. sont prêts à l’avance dans l’instance de destination, cela permet d’éviter dans le fichier de log de l’import les erreurs IMP-00017 et IMP-00003 et devoir réattribuer par la suite les droits et privilèges nécessaires : en voici des exemples

Compte inexistant :

IMP-00017: following statement failed with ORACLE error 1917:
 "GRANT SELECT ON "AMRECON_FORMAT_POS_PERTINENCE" TO "RISK_CONSULT""
IMP-00003: ORACLE error 1917 encountered
ORA-01917: user or role 'RISK_CONSULT' does not exist

Privilèges insuffisants :

IMP-00003: ORACLE error 1950 encountered
ORA-01950: no privileges on tablespace 'USERS'

La création de la base de données de l’instance 2 n’est pas évoquée ici.

L’export de l’instance 1 a été réalisé avec la commande exp ci-dessous :

oracle[INSTANCE1]> exp "'/ as sysdba'" FILE=INSTANCE1.dmp LOG=INSTANCE1.log FULL=Y

Il s’agit d’un export complet (full) de l’instance 1, export pour lequel l’option CONSISTENT=Y n’a pas été appliquée car les tablespaces ont été mis en mode lecture seule (READ ONLY) durant l’export.

L’import dans l’instance 2 est réalisé schéma par schéma avec le commande imp ci-dessous :

oracle[INSTANCE2]> imp "'/ as sysdba'" FILE=INSTANCE1.dmp LOG=<schema>.log \
                                       FROMUSER=<schema> TOUSER=<schema> COMMIT=Y

Les schémas systèmes ne sont pas importés.

2 méthodes sont étudiées pour réaliser le reverse :

  • Reverse à partir des vues du dictionnaire Oracle dans l’instance source INSTANCE1.
  • Reverse à partir d’un export "squelette" de l’instance source INSTANCE1. Pour cette méthode, la plateforme est de type Unix.

Un script shell pour générer automatiquement les scripts SQL de création des profils, des comptes, des rôles, des privilèges, des synonymes publics et privés, des droits, etc. est proposé en annexe pour la méthode s’appuyant sur les vues du dictionnaire.

Création d’un export squelette ou export DDL de l’instance source

En spécifiant ROWS=N dans la commande d’export d’une instance en mode FULL, l’export obtenu ne contient que les commandes DDL (Data Definition Language) comme CREATE USER, CREATE TABLE, etc.

oracle[INSTANCE1]> exp "'/ as sysdba'" FILE=INSTANCE1_SKELETON.dmp \
                                          LOG=INSTANCE1_SKELETON.log FULL=Y ROWS=N

L’export des commandes DDL est lisible et exploitable avec des commandes Unix comme awk, sed, grep, etc. pour extraire les informations nécessaires.

Génération des profils, "reverse" des commandes CREATE PROFILE

Le script de création des profils est exécuté sur l’instance cible avant l’import.

À partir des vues du dictionnaire

Les définitions des profils personnalisés sont récupérées à partir de la vue DBA_PROFILES en écartant la génération pour le profil système DEFAULT.

Les commandes CREATE PROFILE sont d’abord générées avec l’option LIMIT CPU_PER_SESSION DEFAULT car une option LIMIT au moins est obligatoire lors de la commande CREATE PROFILE. Les valeurs des autres options pour les profils sont ensuite mises à jour avec les commandes ALTER PROFILE générées également depuis la vue DBA_PROFILES.

oracle[INSTANCE1]> sqlplus "/ as sysdba"

set heading off;
set feedback off;
set linesize 800;
set pagesize 500;

select distinct 'CREATE PROFILE "'||profile||'" LIMIT CPU_PER_SESSION DEFAULT;' 
from dba_profiles
where profile != 'DEFAULT';

select  'ALTER PROFILE "'||profile||'" LIMIT '||RESOURCE_NAME||' '||LIMIT||';'
from dba_profiles
where profile !='DEFAULT' 
order by profile, resource_name;
…
CREATE PROFILE "SOP_PROFILE" LIMIT CPU_PER_SESSION DEFAULT;
…
ALTER PROFILE "SOP_PROFILE" LIMIT IDLE_TIME 2880;
…

À partir de l’export DDL

À partir de l’export, il suffit de rechercher le mot clé CREATE PROFILE (la création du profil DEFAULT n’est pas consignée dans l’export).

oracle[INSTANCE1]> cat INSTANCE1_SKELETON.dmp | grep -i 'create profile' | awk '{print $0";"}'
          CREATE PROFILE "SOP_PROFILE" LIMIT COMPOSITE_LIMIT DEFAULT 
SESSIONS_PER_USER DEFAULT CPU_PER_SESSION DEFAULT CPU_PER_CALL DEFAULT 
LOGICAL_READS_PER_SESSION DEFAULT LOGICAL_READS_PER_CALL DEFAULT 
IDLE_TIME 2880 CONNECT_TIME DEFAULT PRIVATE_SGA DEFAULT 
FAILED_LOGIN_ATTEMPTS DEFAULT PASSWORD_LIFE_TIME DEFAULT 
PASSWORD_REUSE_TIME DEFAULT PASSWORD_REUSE_MAX DEFAULT 
PASSWORD_LOCK_TIME DEFAULT PASSWORD_GRACE_TIME DEFAULT;

Génération des comptes, "reverse" des commandes CREATE USER

Le script de création des comptes est exécuté sur l’instance cible avant l’import.

À partir des vues du dictionnaire

La vue DBA_USERS est utilisée sur l’environnement source pour réaliser le reverse SQL de création des comptes avec les commandes CREATE USER en conservant les mots de passe, le tablespace de données par défaut, le tablespace temporaire par défaut, le profil. Les comptes systèmes Oracle sont écartés dans la génération :

oracle[INSTANCE1]> sqlplus "/ as sysdba"

set heading off;
set feedback off;
set linesize 800;
set pagesize 500;

select 'CREATE USER "'||username||'" IDENTIFIED BY VALUES '''||password||''' DEFAULT TABLESPACE "'||default_tablespace||'" TEMPORARY TABLESPACE
"'||temporary_tablespace||'" ' ||decode(profile,'DEFAULT','','PROFILE "'||profile||'"')
||' ;' from dba_users
where username not in
(
   'SYS', 'OUTLN', 'SYSTEM', 'CTXSYS', 'DBSNMP',
   'LOGSTDBY_ADMINISTRATOR', 'ORDSYS',
   'ORDPLUGINS',  'OEM_MONITOR', 'WKSYS', 'WKPROXY',
   'WK_TEST', 'WKUSER', 'MDSYS', 'LBACSYS', 'DMSYS',
   'WMSYS',  'OLAPDBA', 'OLAPSVR', 'OLAP_USER',
   'OLAPSYS', 'EXFSYS', 'SYSMAN', 'MDDATA',
   'SI_INFORMTN_SCHEMA', 'XDB', 'ODM','ORACLE_OCM','DIP',
   'TSMSYS','TRACESVR','PERFSTAT'
)
…
CREATE USER "SOP_MODIF" IDENTIFIED BY VALUES 'C632850999096E40' 
DEFAULT TABLESPACE "USERS" TEMPORARY TABLESPACE "TEMP"
PROFILE "SOP_PROFILE" ;
…

À partir de l’export DDL

À partir de l’export DDL, le mot clé CREATE USER est recherché en écartant les comptes systèmes :

oracle[INSTANCE1]> cat INSTANCE1_SKELETON.dmp | grep -i 'create user' | \
egrep -iv 'SYS|OUTLN|SYSTEM|CTXSYS|DBSNMP|\
LOGSTDBY_ADMINISTRATOR|ORDSYS|\
ORDPLUGINS|OEM_MONITOR|WKSYS|WKPROXY|\
WK_TEST|WKUSER|MDSYS|LBACSYS|DMSYS|\
WMSYS|OLAPDBA|OLAPSVR|OLAP_USER|\
OLAPSYS|EXFSYS|SYSMAN|MDDATA|\
SI_INFORMTN_SCHEMA|XDB|ODM|ORACLE_OCM|DIP|\
TSMSYS|TRACESVR|PERFSTAT'|\
awk '{print $0";"}'
…
CREATE USER "RISK" IDENTIFIED BY VALUES '301A0E1D8E9EB50E' DEFAULT TABLESPACE "USERS" 
TEMPORARY TABLESPACE "TEMP" PROFILE "SOP_PROFILE";
…

Génération des rôles, "reverse" des commandes CREATE ROLE

Le script de création des rôles est exécuté sur l’instance cible avant l’import.

À partir des vues du dictionnaire

Pour réaliser le reverse SQL des rôles applicatifs, les vues DBA_ROLES, ROLE_SYS_PRIVS et ROLE_TAB_PRIVS sont interrogées :

oracle[INSTANCE1]> sqlplus "/ as sysdba"

set heading off;
set feedback off;
set linesize 800;
set pagesize 500;
select 'CREATE ROLE "'||role||'";' from dba_roles
where role not in (select distinct role from role_sys_privs)
and role not in (select distinct role from role_tab_privs)
and role != 'GLOBAL_AQ_USER_ROLE'
CREATE ROLE "RISK_MODIF";
CREATE ROLE "RISK_CONSULT";

À partir de l’export DDL

Le mot clé CREATE ROLE est recherché en écartant les rôles systèmes. Dans l’exemple ci-dessous, aucun rôle utilisateur n’a une nomenclature qui s’apparente à la nomenclature des rôles systèmes (AQ_, _CATALOG_, etc.).

oracle[INSTANCE1]> cat INSTANCE1_SKELETON.dmp | grep -i 'create role' | \
egrep -iv 'SECURITY_|LOGSTDBY_|SCHEDULER|_CATALOG_|AQ_|OEM_|HS_|PLUSTRACE|STATISTICS' | \
awk '{print $0";"}'
…
CREATE ROLE "RISK_MODIF";
…

Génération des privilèges pour les rôles et comptes, "reverse" des commandes GRANT <role> to <account|role>

Le script d’attribution des privilèges est exécuté sur l’instance cible avant l’import.

Pour réaliser l’attribution des privilèges de type CONNECT, RESOURCE, etc. aux rôles et comptes, le reverse peut être réalisé depuis la vue DBA_ROLE_PRIVS en écartant les rôles et comptes systèmes Oracle :

oracle[INSTANCE1]> sqlplus "/ as sysdba"

set heading off;
set feedback off;
set linesize 800;
set pagesize 2000;
select 'GRANT "'||granted_role||'" TO "'||grantee||'";' from dba_role_privs
where grantee not in (select distinct role from role_sys_privs)
and grantee not in (select distinct role from role_tab_privs)
and grantee not in (
'SYS', 'OUTLN', 'SYSTEM', 'CTXSYS', 'DBSNMP',
                        'LOGSTDBY_ADMINISTRATOR', 'ORDSYS',
                        'ORDPLUGINS',  'OEM_MONITOR', 'WKSYS', 'WKPROXY',
                        'WK_TEST', 'WKUSER', 'MDSYS', 'LBACSYS', 'DMSYS',
                        'WMSYS',  'OLAPDBA', 'OLAPSVR', 'OLAP_USER',
                        'OLAPSYS', 'EXFSYS', 'SYSMAN', 'MDDATA',
                        'SI_INFORMTN_SCHEMA', 'XDB', 'ODM','ORACLE_OCM','DIP',
                        'TSMSYS','TRACESVR','PERFSTAT')
GRANT "CONNECT" TO "SOP_TRT";
GRANT "CONNECT" TO "SOP_AHEAD";
…

La génération des privilèges attribués aux comptes et rôles est très ardue depuis un fichier d’export DDL.

Génération des synonymes publics, "reverse" des commandes CREATE PUBLIC SYNONYM

Le script de création des synonymes publics est exécuté après l’import dans l’instance cible.

À partir des vues du dictionnaire

Les synonymes publiques sont générés automatiquement à partir de la vue DBA_SYNONYMS en sélectionnant les synonymes dont le propriétaire est PUBLIC et en écartant les objets (table_name) appartenant aux comptes systèmes Oracle. La taille de page (set pagesize) doit être ajustée en fonction du nombre de synonymes publics :

oracle[INSTANCE1]> sqlplus "/ as sysdba"

set heading off;
set feedback off;
set linesize 800;
set pagesize 50000;
select 'CREATE PUBLIC SYNONYM "'||synonym_name||'" FOR "'||table_owner||'"."'||table_name||'";' 
from dba_synonyms
where owner ='PUBLIC'
and table_owner not in (
'SYS', 'OUTLN', 'SYSTEM', 'CTXSYS', 'DBSNMP',
                        'LOGSTDBY_ADMINISTRATOR', 'ORDSYS',
                        'ORDPLUGINS',  'OEM_MONITOR', 'WKSYS', 'WKPROXY',
                        'WK_TEST', 'WKUSER', 'MDSYS', 'LBACSYS', 'DMSYS',
                        'WMSYS',  'OLAPDBA', 'OLAPSVR', 'OLAP_USER',
                        'OLAPSYS', 'EXFSYS', 'SYSMAN', 'MDDATA',
                        'SI_INFORMTN_SCHEMA', 'XDB', 'ODM','ORACLE_OCM','DIP',
                        'TSMSYS','TRACESVR','PERFSTAT')
CREATE PUBLIC SYNONYM "TITRES" FOR "RISK"."TITRES";
…

À partir de l’export DDL

À partir de l’export DDL, le mot clé CREATE PUBLIC SYNONYM est recherché en écartant les synonymes publics pour les compes SYS, SYSTEM, PERFSTAT ainsi que les synonymes publics ayant une nomenclature OL$%, %$LOB, etc.

oracle[INSTANCE1]> cat INSTANCE1_SKELETON.dmp | grep -i 'create public synonym ' |\
egrep -iv '"SYS".|"SYSTEM".|"PERFSTAT".|OL\$|\$LOB|"PRODUCT_PRIVS"' |\
awk '{print $0";"}'
…
CREATE PUBLIC SYNONYM "TITRES" FOR "RISK"."TITRES";
…

Génération des synonymes privés, "reverse" des commandes CREATE SYNONYM

Les synonymes privés sont créés lors de l’import des schémas. La génération des commandes de création des synonymes privés est donnée ici à titre informatif.

Comme pour les synonymes publics, les synonymes privés sont générés à partir de la vue DBA_SYNONYMS en sélectionnant les synonymes pour lesquels les propriétaire du synonyme et de l’objet (table_name) ne sont pas PUBLIC ou un compte système Oracle. La taille de page (set pagesize) doit être ajustée en fonction du nombre de synonymes privés :

oracle[INSTANCE1]> sqlplus "/ as sysdba"

set heading off;
set feedback off;
set linesize 800;
set pagesize 50000;
select 'CREATE SYNONYM "'||owner||'"."'||synonym_name||'" for "'||table_owner||'"."'||table_name||
'";' 
from dba_synonyms
where owner not in (
'SYS', 'OUTLN', 'SYSTEM', 'CTXSYS', 'DBSNMP',
                        'LOGSTDBY_ADMINISTRATOR', 'ORDSYS',
                        'ORDPLUGINS',  'OEM_MONITOR', 'WKSYS', 'WKPROXY',
                        'WK_TEST', 'WKUSER', 'MDSYS', 'LBACSYS', 'DMSYS',
                        'WMSYS',  'OLAPDBA', 'OLAPSVR', 'OLAP_USER',
                        'OLAPSYS', 'EXFSYS', 'SYSMAN', 'MDDATA',
                        'SI_INFORMTN_SCHEMA', 'XDB', 'ODM','ORACLE_OCM','DIP',
                        'TSMSYS','TRACESVR','PERFSTAT'
)
and table_owner not in (
'SYS', 'OUTLN', 'SYSTEM', 'CTXSYS', 'DBSNMP',
                        'LOGSTDBY_ADMINISTRATOR', 'ORDSYS',
                        'ORDPLUGINS',  'OEM_MONITOR', 'WKSYS', 'WKPROXY',
                        'WK_TEST', 'WKUSER', 'MDSYS', 'LBACSYS', 'DMSYS',
                        'WMSYS',  'OLAPDBA', 'OLAPSVR', 'OLAP_USER',
                        'OLAPSYS', 'EXFSYS', 'SYSMAN', 'MDDATA',
                        'SI_INFORMTN_SCHEMA', 'XDB', 'ODM','ORACLE_OCM','DIP',
                        'TSMSYS','TRACESVR','PERFSTAT'
)
and owner !='PUBLIC';
CREATE SYNONYM "RISK_PURGE"."EXTRNL_REFERENCES_AUDIT" for "RISK"."EXTRNL_REFERENCES_AUDIT";
…

La génération des synonymes privés à partir de l’export DDL est nettement moins aisée. La commande CONNECT <schema>; est en effet lancée en amont des commandes CREATE SYNONYM lors d’un import, ainsi le synonyme n’est pas préfixé par le nom du schéma à sa création.

CONNECT RISK
...
CREATE SYNONYM "MAJHISTOTAUX" FOR "RISK"."MAJHISTOTAUX"

Génération des droits, "reverse" des commandes GRANT SELECT, INSERT.... ON

Comme pour les synonymes privés, les droits (SELECT, INSERT, EXECUTE…) sont attribués lors de l’import des schémas. La génération des commandes GRANT est donnée ici à titre informatif.

Les droits sont très facilement générés à partir de la vue DBA_TAB_PRIVS en écartant les comptes Oracle systèmes. Malgré la nomenclature _TAB_ qui peut faire penser aux privilèges sur les tables, cette vue contient également les privilèges sur les vues, procédures, fonctions, packages, etc. Cette fois encore le paramètre pagesize dans la session SQL*Plus doit être adapté au nombre d’objets et de privilèges.

oracle[INSTANCE1]> sqlplus "/ as sysdba"

set heading off;
set feedback off;
set linesize 800;
set pagesize 50000;
select 'GRANT '||privilege||' ON "'||owner||'"."'||table_name||'" TO "'||grantee||'"'||decode(grantable, 'YES', ' WITH GRANT OPTION')
from dba_tab_privs
where owner not in (
'SYS', 'OUTLN', 'SYSTEM', 'CTXSYS', 'DBSNMP',
                        'LOGSTDBY_ADMINISTRATOR', 'ORDSYS',
                        'ORDPLUGINS',  'OEM_MONITOR', 'WKSYS', 'WKPROXY',
                        'WK_TEST', 'WKUSER', 'MDSYS', 'LBACSYS', 'DMSYS',
                        'WMSYS',  'OLAPDBA', 'OLAPSVR', 'OLAP_USER',
                        'OLAPSYS', 'EXFSYS', 'SYSMAN', 'MDDATA',
                        'SI_INFORMTN_SCHEMA', 'XDB', 'ODM','ORACLE_OCM','DIP',
                        'TSMSYS','TRACESVR','PERFSTAT')
GRANT SELECT ON "RISK"."EXTRNL_REFERENCES_AUDIT" TO "RISK_PURGE";
GRANT UPDATE ON "RISK"."EXTRNL_REFERENCES_AUDIT" TO "RISK_PURGE";
…
GRANT SELECT ON "RISK"."EXTRNL_REFERENCES_AUDIT" TO "RISK_CONSULT";
…
GRANT EXECUTE ON "RISK"."INSERTDIVIDENDS2" TO "RISK_CONSULT";
…

Comme pour les synonymes privés, la génération des droits à partir de l’export DDL est difficile. Les objets dans les commandes GRANT <priv> TO lors d’un import ne sont pas préfixés par le nom du schéma.

CONNECT RISK
…
GRANT EXECUTE ON "NUM_TO_DATE" TO "RISK_CONSULT"

rvaccountsprivs.ksh

#!/bin/ksh
# SPA
# 08/2009
# Outil de reverse pour les exports/imports
# Reverse des comptes, roles et privileges
# Reverse des synonymes

INST_SOURCE=$1

if [ ! -f ${DBA}/etc/${INST_SOURCE}.inst ]
then
        echo "Instance non existante"
        exit 3
fi

# Prise de l’environnement de l’instance
 . $DBA/etc/${INST_SOURCE}.inst


revprofiles="rev_profiles_${INST_SOURCE}.sql"
revusers="rev_users_${INST_SOURCE}.sql"
revroles="rev_roles_${INST_SOURCE}.sql"
revroleprivs="rev_roleprivs_${INST_SOURCE}.sql"
revpubsyns="rev_pubsyns_${INST_SOURCE}.sql"
revprivsyns="rev_privsyns_${INST_SOURCE}.sql"
revgrants="rev_grants_${INST_SOURCE}.sql"

# Definition d’une liste des comptes systemes Oracle
SYSORAACCOUNTS="'SYS', 'OUTLN', 'SYSTEM', 'CTXSYS', 'DBSNMP', 'LOGSTDBY_ADMINISTRATOR', 'ORDSYS', 'ORDPLUGINS',  'OEM_MONITOR', 'WKSYS', 'WKPROXY', 'WK_TEST', 'WKUSER', 'MDSYS', 'LBACSYS', 'DMSYS', 'WMSYS',  'OLAPDBA', 'OLAPSVR', 'OLAP_USER', 'OLAPSYS', 'EXFSYS', 'SYSMAN', 'MDDATA', 'SI_INFORMTN_SCHEMA', 'XDB', 'ODM','ORACLE_OCM','DIP', 'TSMSYS','TRACESVR','PERFSTAT'"


# 1- Reverse des profils
sqlplus -s "/ as sysdba" EOF > ${SCRIPT}/${revprofiles}
set heading off;
set feedback off;
set pagesize 1000;
set linesize 800;

select distinct 'CREATE PROFILE "'||profile||'" LIMIT CPU_PER_SESSION DEFAULT;' 
from dba_profiles
where profile != 'DEFAULT';

select  'ALTER PROFILE "'||profile||'" LIMIT '||RESOURCE_NAME||' '||LIMIT||';'
from dba_profiles
where profile !='DEFAULT' 
order by profile, resource_name;
EOF

# 2- Reverse des comptes
sqlplus -s "/ as sysdba" EOF > ${SCRIPT}/${revusers}
set heading off;
set feedback off;
set pagesize 1000;
set linesize 800;

select 'CREATE USER "'||username||'" IDENTIFIED BY VALUES '''||password||''' DEFAULT TABLESPACE "'||default_tablespace||'" TEMPORARY TABLESPACE
"'||temporary_tablespace||'" ' ||decode(profile,'DEFAULT','','PROFILE "'||profile||'"')
||' ;' from dba_users
where username not in (${SYSORAACCOUNTS});
EOF

# 3- Reverse des roles applicatifs
sqlplus -s "/ as sysdba" EOF > ${SCRIPT}/${revroles}
set heading off;
set feedback off;
set pagesize 1000;
set linesize 800;
select 'CREATE ROLE "'||role||'";' from dba_roles
where role not in (select distinct role from role_sys_privs)
        and role not in (select distinct role from role_tab_privs)
        and role != 'GLOBAL_AQ_USER_ROLE';
EOF

# 4- Reverse des privileges des roles
sqlplus -s "/ as sysdba" EOF > ${SCRIPT}/${revroleprivs}
set heading off;
set feedback off;
set pagesize 1000;
set linesize 800;
select 'GRANT "'||granted_role||'" TO "'||grantee||'";' from dba_role_privs
where grantee not in (select distinct role from role_sys_privs)
and grantee not in (select distinct role from role_tab_privs)
and grantee not in (${SYSORAACCOUNTS});
EOF

# 5- Reverse des synonymes publics
sqlplus -s "/ as sysdba" EOF > ${SCRIPT}/${revpubsyns}
set heading off;
set feedback off;
set pagesize 50000;
set linesize 800;
select 'CREATE PUBLIC SYNONYM "'||synonym_name||'" for "'||table_owner||'"."'||table_name||'";' 
from dba_synonyms
where owner = 'PUBLIC'
and table_owner not in (${SYSORAACCOUNTS});
EOF

# 6- Reverse des synonymes prives
sqlplus -s "/ as sysdba" EOF > ${SCRIPT}/${revprivsyns}
set heading off;
set feedback off;
set pagesize 50000;
set linesize 800;
select 'CREATE SYNONYM "'||owner||'"."'||synonym_name||'" for "'||table_owner||'"."'||table_name||'";' 
from dba_synonyms
where owner not in (${SYSORAACCOUNTS})
and table_owner not in (${SYSORAACCOUNTS})
and owner !='PUBLIC';
EOF

# 7- Reverse des droits
sqlplus -s "/ as sysdba" EOF > ${SCRIPT}/${revgrants}
set heading off;
set feedback off;
set pagesize 50000;
set linesize 800;
select 'GRANT '||privilege||' ON "'||owner||'"."'||table_name||'" TO "'||grantee||'"'||decode(grantable, 'YES', ' WITH GRANT OPTION')||';'
from dba_tab_privs
where owner not in (${SYSORAACCOUNTS});
EOF