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.