Si vous êtes DBA de prod il est fort probable que pour supprimer des objets d'un schéma applicatif d'une base de données vous utilisiez un compte nominatif avec le role DBA, voir même le compte SYS. La plupart du temps les mots de passe des schémas applicatifs ne sont pas connus des DBAs.
Presque tous les objets d'un schéma peuvent être supprimés avec un autre compte ayant le role DBA en préfixant l'objet par le nom du USER propriétaire. J'ai dit "presque" car ce n'est pas vrai pour les DB Links et les jobs. En effet, il est impossible même pour le user SYS de supprimer un DB Link privé ou un job appartenant à un autre USER.
Voici un exemple concret d'un DB Link que j'ai eu à supprimer ce matin:
Si, en me connectant en sysdba, j'essaye de le supprimer en préfixant le nom du db link par le nom du schéma propriétaire j'obtiens l'erreur suivante:
En modifiant le schéma par défaut au niveau de la session j'obtiens un autre message d'erreur indiquant que je ne suis pas autorisé à supprimer le db link en question:
Il n'est donc pas possible de supprimer un db link privé appartenant à un autre user sauf bien sûr en se connectant avec le user propriétaire directement.
D'ailleurs la doc Oracle est claire à ce sujet:
La doc Oracle ne donne pas de solution de contournement mais comme souvent dans Oracle il existe un moyen officieux d'arriver à ses fins.
Ici la solution va consister à utiliser le package non documenté DBMS_SYS_SQL.
En effet, dans ce package on a la fonction PARSE_AS_USER qui permet d’exécuter une commande SQL en tant que n'importe quel autre user.
Voici le script que j'utilise et que j'ai appelé drop_db_link.sql dans ma toolbox:
Grace au nom du schéma propriétaire il récupère le USER_ID qui sera utilisé comme un des paramètres de la fonction SYS.DBMS_SYS_SQL.parse_as_user.
On peut ainsi exécuter la commande DROP DATABASE LINK comme si on était connecté avec le compte propriétaire:
Après avoir exécuté le script on peut vérifier que le db link a bien été supprimé:
Presque tous les objets d'un schéma peuvent être supprimés avec un autre compte ayant le role DBA en préfixant l'objet par le nom du USER propriétaire. J'ai dit "presque" car ce n'est pas vrai pour les DB Links et les jobs. En effet, il est impossible même pour le user SYS de supprimer un DB Link privé ou un job appartenant à un autre USER.
Voici un exemple concret d'un DB Link que j'ai eu à supprimer ce matin:
SQL>select OWNER,DB_LINK from dba_db_links where DB_LINK='DBL_TEST'; OWNER DB_LINK ------------------------------ ------------------------------ ASDRVMAT DBL_TESTLe DB Link DBL_TEST appartient au schema ASDRVMAT.
Si, en me connectant en sysdba, j'essaye de le supprimer en préfixant le nom du db link par le nom du schéma propriétaire j'obtiens l'erreur suivante:
DROP DATABASE LINK ASDRVMAT.DBL_TEST; ERREUR à la ligne 1 : ORA-02024: lien de base de données introuvableOracle ne trouve pas le db link car il interprète "ASDRVMAT.DBL_TEST" comme étant le nom du db link.
En modifiant le schéma par défaut au niveau de la session j'obtiens un autre message d'erreur indiquant que je ne suis pas autorisé à supprimer le db link en question:
alter session set current_schema=ASDRVMAT; DROP DATABASE LINK DBL_TEST; ERREUR à la ligne 1 : ORA-01031: privilèges insuffisants
Il n'est donc pas possible de supprimer un db link privé appartenant à un autre user sauf bien sûr en se connectant avec le user propriétaire directement.
D'ailleurs la doc Oracle est claire à ce sujet:
Restriction on Dropping Database Links You cannot drop a database link in another user's schema, and you cannot qualify dblink
with the name of a schema, because periods are permitted in names of database links
La doc Oracle ne donne pas de solution de contournement mais comme souvent dans Oracle il existe un moyen officieux d'arriver à ses fins.
Ici la solution va consister à utiliser le package non documenté DBMS_SYS_SQL.
En effet, dans ce package on a la fonction PARSE_AS_USER qui permet d’exécuter une commande SQL en tant que n'importe quel autre user.
Voici le script que j'utilise et que j'ai appelé drop_db_link.sql dans ma toolbox:
declare sql_text varchar2(1000); cur number; user_id number; res number; begin select u.user_id into user_id from dba_users u where u.username = '&schema_name'; sql_text := 'drop database link '||'&db_link'; cur := SYS.DBMS_SYS_SQL.open_cursor; SYS.DBMS_SYS_SQL.parse_as_user( c => cur, statement => sql_text, language_flag => DBMS_SQL.native, userID => user_id ); res := SYS.DBMS_SYS_SQL.execute(cur); SYS.DBMS_SYS_SQL.close_cursor(cur); end; /Ce script prend en paramètre le nom du schéma propriétaire et le nom du db link à dropper.
Grace au nom du schéma propriétaire il récupère le USER_ID qui sera utilisé comme un des paramètres de la fonction SYS.DBMS_SYS_SQL.parse_as_user.
On peut ainsi exécuter la commande DROP DATABASE LINK comme si on était connecté avec le compte propriétaire:
SQL>declare sql_text varchar2(1000); cur number; user_id number; res number; --dblk varchar2(30); begin --dblk := select u.user_id into user_id from dba_users u where u.username = '&schema_name'; sql_text := 'drop database link '||'&db_link'; cur := SYS.DBMS_SYS_SQL.open_cursor; SYS.DBMS_SYS_SQL.parse_as_user( c => cur, statement => sql_text, language_flag => DBMS_SQL.native, userID => user_id ); res := SYS.DBMS_SYS_SQL.execute(cur); SYS.DBMS_SYS_SQL.close_cursor(cur); end; / Entrez une valeur pour schema_name : ASDRVMAT ancien 12 : where u.username = '&schema_name'; nouveau 12 : where u.username = 'ASDRVMAT'; Entrez une valeur pour db_link : DBL_TEST ancien 14 : sql_text := 'drop database link '||'&db_link'; nouveau 14 : sql_text := 'drop database link '||'DBL_TEST'; Procédure PL/SQL terminée avec succès.
Après avoir exécuté le script on peut vérifier que le db link a bien été supprimé:
SQL>select OWNER,DB_LINK from dba_db_links where DB_LINK='DBL_TEST'; aucune ligne sélectionnée
j'ai aussi suggéré sur mon blog dbms_scheduler:
RépondreSupprimerhttp://laurentschneider.com/wordpress/2012/10/drop-database-link-in-another-schema.html
Laurent
Salut Laurent, je n'avais pas pensé à ça.
SupprimerUne 3ème solution serait d'utiliser une connexion proxy
Bonjour,
SupprimerAutre possibilité :
exec sys.kupp$proc.change_user('ASDRVMAT');
va savoir pourquoi, potentiellement tu peux avoir cette erreur
ERROR at line 1:
ORA-31625: Schema SYSTEM is needed to import this object, but is unaccessible
ORA-06512: at "SYS.KUPP$PROC", line 37
ORA-06512: at "SYS.KUPP$PROC", line 597
ORA-06512: at line 1
dans ce cas il faut executer la requete ci-dessous et recommencer
select sys.kupp$proc.disable_multiprocess from dual;
J'ai testé avec un dblink, mais cela doit également fonctionner avec un job.
@+
Laurent
http://www.lao-dba.com
le problème que j'ai avec dbms_scheduler c'est que ça ne marche pas quand l'utilisateur a trop de roles (ora-28031)
RépondreSupprimerquant au proxy, c'est moins pratique, et ça ne marche que si l'utilisateur a CREATE SESSION et est UNLOCK
je pense que je vais donc employer ta soluce avec DBMS_SYS_SQL.parse_as_user :)
Laurent