Oracle
 sql >> Base de données >  >> RDS >> Oracle

Session Oracle impossible à tuer en attente d'un message SQL*Net provenant d'un événement client

Cela semble être un bogue dans Oracle lorsque CLOB les types de données sont utilisés comme valeurs qui sont transmises au MERGE ON de l'instruction clause. Supposons que cette base de données :

CREATE TABLE t (
  v INT, 
  s VARCHAR2(400 CHAR)
);

Reproduction à l'aide de valeurs en ligne

Maintenant, exécutez l'instruction suivante dans n'importe quel client Oracle, y compris SQL*Plus, SQL Developer ou depuis JDBC, ce qui permet de reproduire le problème très facilement (j'utilise Oracle 11g XE 11.2.0.2.0) :

MERGE INTO t                      
USING (
  SELECT 
    1 v, 
    CAST('abc' AS CLOB) s 
  FROM DUAL
) s 
ON (t.s = s.s) -- Using a CLOB here causes the bug.
WHEN MATCHED THEN UPDATE SET
  t.v = s.v        
WHEN NOT MATCHED THEN INSERT (v, s) 
VALUES (s.v, s.s);

L'exemple est idiot, et le CLOB a été lié ici par "accident". Néanmoins, une telle déclaration ne devrait pas créer de session zombie dans Oracle, mais elle existe. J'exécute l'instruction ci-dessus trois fois dans SQL*Plus, puis j'exécute ceci...

SELECT 
  s.sid,
  s.serial#,
  s.sql_id,
  s.event,
  s.blocking_session,
  q.sql_text
FROM v$session s
JOIN v$sql q
ON s.sql_id = q.sql_id
WHERE s.username = 'TEST'
AND UPPER(TRIM(q.sql_text)) LIKE 'MERGE%';

... j'obtiens :

sid serial# sql_id          event                       blocking_session
9   3       82a2k4sqzy1jq   cursor: pin S wait on X     92
49  89      82a2k4sqzy1jq   cursor: pin S wait on X     92
92  13      82a2k4sqzy1jq   db file sequential read     

Remarquez comment l'événement signalé est différent ("db file sequential read" ) à partir de l'événement d'origine ("Message SQL*Net du client" ), qui utilisait des variables de liaison

Reproduction à l'aide de valeurs liées

var v_s varchar2(50)
exec :v_s := 'abc'

MERGE INTO t                      
USING (
  SELECT 
    1 v, 
    CAST(:v_s AS CLOB) s 
  FROM DUAL
) s 
ON (t.s = s.s) -- Using a CLOB here causes the bug.
WHEN MATCHED THEN UPDATE SET
  t.v = s.v        
WHEN NOT MATCHED THEN INSERT (v, s) 
VALUES (s.v, s.s);

L'instruction ci-dessus exécutée dans SQL*Plus génère également le bogue :

sid serial# sql_id          event                           blocking_session
8   1       4w9zuxrumumgj   SQL*Net message from client     
90  7       4w9zuxrumumgj   cursor: pin S wait on X         8
94  21      4w9zuxrumumgj   cursor: pin S wait on X         8

Pas de reproduction en PL/SQL

Fait intéressant, le bogue est évité dans l'instruction PL/SQL suivante :

DECLARE
  v_s CLOB := 'abc';
BEGIN
  MERGE INTO t                      
  USING (
    SELECT 
      1 v, 
      CAST(v_s AS CLOB) s 
    FROM DUAL
  ) s 
  ON (t.s = s.s) -- Using a CLOB here causes the bug.
  WHEN MATCHED THEN UPDATE SET
    t.v = s.v        
  WHEN NOT MATCHED THEN INSERT (v, s) 
  VALUES (s.v, s.s);
END;
/

J'obtiens :

          CAST(v_s AS CLOB) s
          *
ERROR at line 8:
ORA-06550: line 8, column 11:
PL/SQL: ORA-00932: inconsistent datatypes: expected - got CLOB
ORA-06550: line 4, column 7:
PL/SQL: SQL Statement ignored

Il semble que le moteur PL/SQL protège les clients de ce bogue du moteur SQL.