Đây dường như là một lỗi trong Oracle khi CLOB
kiểu dữ liệu được sử dụng làm giá trị được chuyển đến MERGE
của câu lệnh ON
mệnh đề. Giả sử cơ sở dữ liệu này:
CREATE TABLE t (
v INT,
s VARCHAR2(400 CHAR)
);
Sao chép bằng các giá trị nội dòng
Bây giờ, hãy chạy câu lệnh sau trong bất kỳ máy khách Oracle nào, bao gồm SQL * Plus, SQL Developer hoặc từ JDBC, giúp tái tạo sự cố rất dễ dàng (Tôi đang sử dụng 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);
Ví dụ thật ngớ ngẩn và CLOB
đã bị ràng buộc ở đây bởi "tình cờ". Tuy nhiên, một câu lệnh như vậy không nên tạo ra một phiên thây ma trong Oracle, nhưng nó ở đó. Tôi đang chạy câu lệnh trên ba lần trong SQL * Plus và sau đó chạy câu lệnh này ...
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%';
... Tôi nhận được:
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
Lưu ý sự kiện được báo cáo khác nhau như thế nào ( "đọc tuần tự tệp db" ) từ sự kiện ban đầu ( "Thông báo SQL * Net từ máy khách" ), đang sử dụng các biến liên kết
Sao chép sử dụng các giá trị ràng buộc
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);
Câu lệnh trên chạy trong SQL * Plus cũng tạo ra lỗi:
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
Không sao chép trong PL / SQL
Thật thú vị, lỗi được tránh trong câu lệnh PL / SQL sau:
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;
/
Tôi nhận được:
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
Có vẻ như công cụ PL / SQL bảo vệ máy khách khỏi lỗi công cụ SQL này.