Strange deadlock across DB Link

  • From: De DBA <dedba@xxxxxxxxxx>
  • To: "oracle-l@xxxxxxxxxxxxx" <oracle-l@xxxxxxxxxxxxx>
  • Date: Wed, 28 Mar 2018 22:08:59 +1000

G'day.

This has had me stumped all day. I have a requirement to copy new users,  
change account statuses and adjust grants across a number of databases. There 
is one source (the production database) which is the point of truth and all 
lower environments are managed from this source.

Up to now, the process simply drops all users and runs an import from the 
production database. As this is a bit crude, I am trying to device a more 
gentle process where we can have users in lower environments that don't 
necessarily exist in the source, e.g. for new projects.

The solution that I am working towards is a pl/sql block that uses a number of 
dictionary tables, both over a database link and local. The problem that I 
encounter is this:


declare
*
ERROR at line 1:
ORA-04052: error occurred when looking up remote object 
SYS.DBA_ROLE_PRIVS@DB_LINK
ORA-04020: deadlock detected while trying to lock object SYS.USER$@DB_LINK

It is not consistent - sometimes I can run the program for an hour or so 
without the deadlock occurring. I have determined that this occurs in the 
declaration of the cursors, it even happens when the body is null. Commenting 
one or more cursors will make the error also go away.

Even stranger is that although Oracle reports a deadlock, no message is logged 
in the alert log on the local database or the remote.

Below is the code:


  1  declare
  2      -- 0.0 list roles that do not exist in this db
  3      cursor cNewRole is
  4          select 'create role '||role as stmt
  5            from sys.dba_roles@DB_LINK
  6          minus
  7          select 'create role '||role as stmt
  8            from dba_roles;
  9      -- 0.1 identify remote ordinary users, and account status
10      cursor cRmtUsr is
11          select u.name                    as username
12               , u.password||';'||u.spare4 as pwdhash
13               , m.status                  as actst
14               , case
15                   when u.astatus in ( 1,  2 )    then 'PASSWORD EXPIRE'
16                   when u.astatus in ( 8 )        then 'ACCOUNT LOCK'
17                   when u.astatus in ( 5,6,9,10 ) then 'ACCOUNT LOCK PASSWORD 
EXPIRE'
18                   else 'OPEN'
19                 end                       as actact
20               , dts.name                  as deftbs
21               , tts.name                  as tmptbs
22          from sys.user$@DB_LINK u
23             , sys.user_astatus_map m
24             , sys.ts$@DB_LINK   dts
25             , sys.ts$@DB_LINK   tts
26         where m.status#  = u.astatus
27           and dts.ts#    = u.datats#
28           and tts.ts#    = u.tempts#
29           and dts.name   not in ( 'SYSTEM', 'SYSAUX', 'TOOLS', 'XDB', 
'ADHOC' )
30           and u.name     not in ( 'DBSNMP', 'XS$NULL' )
31           and u.name     not like 'ABC-%'
32         ;
33      -- 0.2 check if a user exists in this DB and get the account status
34      cursor cExist ( bUid varchar2 ) is
35          select account_status
36            from sys.dba_users
37           where username  = bUid;
38      -- 0.3 Retrieve a list of privileges that are granted to the user 
locally
39      cursor cPrivs ( bUid varchar2 ) is
40          select granted_role as priv
41            from sys.dba_role_privs
42           where grantee = bUid
43         union
44          select privilege
45            from sys.dba_sys_privs
46           where grantee = bUid
47         union
48          select listagg(privilege, ', ') within group ( order by owner, 
table_name )
49                 || ' on ' ||owner||'.'||table_name
50            from sys.dba_tab_privs
51           where grantee = bUid
52             and owner   not in ( 'SYS', 'SYSTEM' )
53           group by owner, table_name
54         ;
55      -- 0.4 Create a table of privileges for the user in the source (remote) 
database
56      cursor cPrivsRem ( bUid varchar2 ) is
57          select granted_role as priv
58            from sys.dba_role_privs@DB_LINK
59           where grantee = bUid
60         union
61          select privilege
62            from sys.dba_sys_privs@DB_LINK
63           where grantee = bUid
64         union
65          select listagg(privilege, ', ') within group ( order by owner, 
table_name )
66                 || ' on ' ||owner||'.'||table_name
67            from sys.dba_tab_privs@DB_LINK
68           where grantee = bUid
69             and owner   not in ( 'SYS', 'SYSTEM' )
70           group by owner, table_name
71         ;
72 begin
73    null;
74 end;
75 /

Cheers,

Tony

--
//www.freelists.org/webpage/oracle-l


Other related posts:

  • » Strange deadlock across DB Link - De DBA