Ini tampaknya menjadi bug di Oracle ketika CLOB
tipe data digunakan sebagai nilai yang diteruskan ke MERGE
pernyataan ON
ayat. Asumsikan database ini:
CREATE TABLE t (
v INT,
s VARCHAR2(400 CHAR)
);
Reproduksi menggunakan nilai sebaris
Sekarang, jalankan pernyataan berikut di setiap klien Oracle, termasuk SQL*Plus, SQL Developer atau dari JDBC, yang membantu mereproduksi masalah dengan sangat mudah (Saya menggunakan 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);
Contohnya konyol, dan CLOB
terikat di sini oleh "kecelakaan". Meskipun demikian, pernyataan seperti itu seharusnya tidak membuat sesi zombie di Oracle, tetapi ada di sana. Saya menjalankan pernyataan di atas tiga kali di SQL*Plus dan kemudian menjalankan ini...
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%';
... Saya mendapatkan:
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
Perhatikan perbedaan peristiwa yang dilaporkan ("pembacaan berurutan file db" ) dari acara asli ("SQL*Net message from client" ), yang menggunakan variabel bind
Reproduksi menggunakan nilai ikatan
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);
Pernyataan di atas yang dijalankan di SQL*Plus juga menghasilkan 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
Tidak ada reproduksi di PL/SQL
Menariknya, bug tersebut dihindari dalam pernyataan PL/SQL berikut:
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;
/
Saya mendapatkan:
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
Sepertinya mesin PL/SQL menyelamatkan klien dari bug mesin SQL ini.