Dit lijkt een bug te zijn in Oracle wanneer CLOB
gegevenstypen worden gebruikt als waarden die worden doorgegeven aan de MERGE
statement is ON
clausule. Stel deze database:
CREATE TABLE t (
v INT,
s VARCHAR2(400 CHAR)
);
Reproductie met inline-waarden
Voer nu de volgende instructie uit in een Oracle-client, inclusief SQL*Plus, SQL Developer of vanuit JDBC, waardoor het probleem heel gemakkelijk kan worden gereproduceerd (ik gebruik 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);
Het voorbeeld is dwaas, en de CLOB
was hier gebonden door "ongeluk". Desalniettemin zou zo'n statement geen zombiesessie in Oracle moeten creëren, maar het is er wel. Ik voer de bovenstaande instructie drie keer uit in SQL*Plus en voer vervolgens dit uit...
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%';
... ik krijg:
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
Merk op hoe de gerapporteerde gebeurtenis anders is ("db file sequentiële read" ) van de oorspronkelijke gebeurtenis ("SQL*Net-bericht van client" ), die bindvariabelen gebruikte
Reproductie met bindingswaarden
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);
De bovenstaande instructie uitgevoerd in SQL*Plus produceert ook de bug:
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
Geen reproductie in PL/SQL
Interessant is dat de bug wordt vermeden in de volgende PL/SQL-verklaring:
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;
/
Ik krijg:
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
Het lijkt erop dat de PL/SQL-engine klanten behoedt voor deze bug in de SQL-engine.