ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion は、Oracleで CLOB を CHAR/VARCHAR2 へ、または BLOB を RAW へ変換しようとした時に、変換先のバッファ上限よりLOBデータが大きい場合に発生するエラーです。
よくある原因は、TO_CHAR(clob_column)、CLOB列への REGEXP_REPLACE、XMLTYPE やJSON処理で暗黙的にVARCHAR2へ変換されるケース、BLOBをRAWとして一括取得しようとするケースです。CLOB列だから大容量を保存できても、途中でVARCHAR2へ変換すると上限に当たります。
CLOBやBLOBを丸ごと
TO_CHAR / RAW に変換しないことが基本です。短く切り出すなら DBMS_LOB.SUBSTR、全量を扱うならCLOB/BLOBのまま処理する、画面・CSV・ログ出力なら分割読み出しにします。ORA-22835とは
Oracle公式の説明では、ORA-22835はCLOBをCHARへ、またはBLOBをRAWへ変換しようとした際、LOBサイズがCHAR/RAW型のバッファ上限を超えた場合に発生します。エラーメッセージには actual と maximum が表示され、実データサイズと変換先上限を確認できます。
LOBの基本は LOB(CLOB/BLOB/BFILE)完全ガイド、DBMS_LOB の使い方は DBMS_LOB完全ガイド を参照してください。
エラーメッセージの読み方
ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion (actual: 6842, maximum: 4000)
actual は変換しようとしたLOB側のサイズ、maximum は変換先バッファの上限です。maximum: 4000 ならSQL上のVARCHAR2上限、maximum: 32767 ならPL/SQL変数や関数戻り値の上限が関係している可能性があります。
SQLとPL/SQLで上限が違う
ORA-22835では、同じCLOBでも実行場所によって上限の見え方が変わります。SQL文のSELECT結果としてVARCHAR2へ変換する場合と、PL/SQL変数へ一時的に受ける場合では、扱えるサイズが異なるためです。
SQLで変換している場合
SELECT句やWHERE句の中で TO_CHAR(CLOB) や暗黙的なVARCHAR2変換が起きると、4000バイト上限に当たりやすくなります。
PL/SQLで受けている場合
VARCHAR2(32767) など、SQLより大きな変数で受けられる場面があります。ただしCLOB全量を受ける設計には向きません。
MAX_STRING_SIZE=EXTENDED
上限が広がる環境もありますが、LOB全体を文字列型へ変換する発想は残るため、数万バイトを超えるCLOBでは根本対策になりません。
-- SQL上で丸ごと変換しない SELECT DBMS_LOB.SUBSTR(body_clob, 4000, 1) AS preview_text FROM message_log; -- PL/SQLでも全量をVARCHAR2へ入れるのではなく、必要な単位で処理する
よくあるNG例: TO_CHAR(CLOB)
CLOB列を検索・表示・加工するために TO_CHAR で丸ごと変換すると、4000バイトを超えるデータでORA-22835になりやすいです。
SELECT id,
TO_CHAR(body_clob) AS body_text
FROM message_log;
短いプレビューだけ必要なら、DBMS_LOB.SUBSTR で必要な範囲だけ切り出します。
SELECT id,
DBMS_LOB.SUBSTR(body_clob, 4000, 1) AS body_preview
FROM message_log;
DBMS_LOB.SUBSTRを使う時の注意
DBMS_LOB.SUBSTR は便利ですが、戻り値をVARCHAR2として受ける以上、取り出せる長さには上限があります。また、日本語などマルチバイト文字では、文字数とバイト数の違いにも注意します。
SELECT id,
DBMS_LOB.GETLENGTH(body_clob) AS clob_length,
LENGTHB(DBMS_LOB.SUBSTR(body_clob, 4000, 1)) AS preview_bytes
FROM message_log
WHERE id = :id;
DBMS_LOB.SUBSTR は「指定範囲を切り出す」方法です。CLOB全体を必要とする処理では、分割して読むか、CLOBのままアプリやPL/SQLで扱います。文字数とバイト数の確認は LENGTH / LENGTHBで文字数・バイト数を取得する方法 も参考になります。
CLOBを分割して読み出す
CLOBを全量出力したい場合は、1回でVARCHAR2へ変換せず、複数回に分けて読み出します。PL/SQLでは、チャンクサイズを決めて DBMS_LOB.SUBSTR をループします。
DECLARE
v_clob CLOB;
v_pos PLS_INTEGER := 1;
v_chunk VARCHAR2(32767);
v_amount PLS_INTEGER := 32000;
BEGIN
SELECT body_clob
INTO v_clob
FROM message_log
WHERE id = :id;
LOOP
v_chunk := DBMS_LOB.SUBSTR(v_clob, v_amount, v_pos);
EXIT WHEN v_chunk IS NULL;
DBMS_OUTPUT.PUT_LINE(SUBSTR(v_chunk, 1, 32767));
v_pos := v_pos + v_amount;
END LOOP;
END;
/
全量をファイルへ出したい場合
ログ退避や調査用にCLOB全体を出力したい場合も、SQLで一括変換するのではなく、チャンク単位で読みながらファイルへ書き出します。Oracleディレクトリオブジェクトと権限が必要なため、本番では出力先と権限を事前に確認してください。
DECLARE
v_clob CLOB;
v_pos PLS_INTEGER := 1;
v_chunk VARCHAR2(32767);
v_amount PLS_INTEGER := 32000;
v_file UTL_FILE.FILE_TYPE;
BEGIN
SELECT body_clob
INTO v_clob
FROM message_log
WHERE id = :id;
v_file := UTL_FILE.FOPEN('LOG_DIR', 'message_body.txt', 'W', 32767);
LOOP
v_chunk := DBMS_LOB.SUBSTR(v_clob, v_amount, v_pos);
EXIT WHEN v_chunk IS NULL;
UTL_FILE.PUT(v_file, v_chunk);
v_pos := v_pos + v_amount;
END LOOP;
UTL_FILE.FCLOSE(v_file);
END;
/
UTL_FILE.PUT_LINE(TO_CHAR(body_clob)) のように書くと、出力前にVARCHAR2変換が発生して同じエラーになります。LOBは読み出し単位を小さくして、順番に処理します。REGEXP_REPLACEやREPLACEで発生する場合
CLOB列の改行除去やHTMLタグ除去で、関数の途中結果がVARCHAR2へ寄せられるとORA-22835になることがあります。短い範囲だけ加工するのか、CLOB全体を加工してCLOBへ戻すのかを分けて考えます。
SELECT id,
TO_CHAR(REGEXP_REPLACE(body_clob, '<[^>]+>', '')) AS plain_text
FROM message_log;
SELECT id,
REGEXP_REPLACE(DBMS_LOB.SUBSTR(body_clob, 4000, 1), '<[^>]+>', '') AS plain_preview
FROM message_log;
改行や文字列置換の実務パターンは 改行コードを置換・削除する方法完全ガイド も参照してください。
BLOB to RAWで発生する場合
BLOBをRAWへ一括変換しようとした場合も、RAW型の上限を超えるとORA-22835になります。画像やPDFなどのバイナリをSQLで丸ごとRAW化するのではなく、必要な範囲だけ切り出すか、BLOBとしてアプリケーション側へ渡します。
SELECT id,
DBMS_LOB.SUBSTR(file_blob, 2000, 1) AS raw_preview
FROM file_store
WHERE id = :id;
XMLやJSON処理で発生する場合
XMLやJSONをCLOBで保持している場合、途中でVARCHAR2へ変換する関数や式を挟むとORA-22835になることがあります。全体を文字列化するのではなく、必要な要素だけを取り出す、CLOB対応の関数を使う、アプリ側でパースするなどの方針に分けます。
プレビュー表示
DBMS_LOB.SUBSTR で先頭数千文字だけを取得します。検索結果一覧やログ確認に向いています。
値の抽出
JSON_VALUE、XMLTABLE、XMLQUERYなどで必要な項目だけを取り出します。CLOB全体をTO_CHARしないようにします。
全量出力
CLOBとしてアプリへ渡す、または分割して読み出します。SQL上でVARCHAR2へ一括変換しないようにします。
XML処理は XMLType完全ガイド、JSON処理は JSON完全ガイド も参考になります。
暗黙変換しているSQLを探す
アプリから実行されたSQLで発生している場合、ソースだけを見ても原因箇所を見つけにくいことがあります。V$SQL から TO_CHAR、DBMS_LOB.SUBSTR、REGEXP_REPLACE などを含むSQLを探すと、CLOBをVARCHAR2へ寄せている箇所を絞り込めます。
SELECT sql_id,
parsing_schema_name,
last_active_time,
sql_text
FROM v$sql
WHERE UPPER(sql_text) LIKE '%TO_CHAR%'
OR UPPER(sql_text) LIKE '%DBMS_LOB.SUBSTR%'
OR UPPER(sql_text) LIKE '%REGEXP_REPLACE%'
ORDER BY last_active_time DESC
FETCH FIRST 50 ROWS ONLY;
実行中・実行済みSQLの確認方法は V$SQLAREA / V$SQLTEXTで実行SQLを確認する方法 も参考になります。
ORA-01704との違い
ORA-22835
保存済みのCLOB/BLOBなどを、CHAR/VARCHAR2/RAWへ変換する時に変換先上限を超えて発生します。
ORA-01704
SQL文に直接書いた文字列リテラルが長すぎる時に発生します。詳細は ORA-01704の原因と解決方法 を参照してください。
ORA-01489
LISTAGGなどの文字列結合結果が長すぎる時に発生します。CLOB変換ではなく、集約結果の上限を確認します。
修正の流れ
- エラーの
actualとmaximumを確認する - SQL内に
TO_CHAR(CLOB)やBLOBからRAWへの一括変換がないか探す - プレビューだけなら
DBMS_LOB.SUBSTRで必要な長さに制限する - 全量が必要ならCLOB/BLOBのまま扱うか、分割して読み出す
- REGEXP_REPLACE、XML、JSON処理で暗黙変換が起きていないか確認する
- アプリ側でLOBを受け取れる型・APIを使っているか確認する
よくある質問
CLOBなのに4000バイトでエラーになるのはなぜですか?
CLOB自体の容量ではなく、途中でVARCHAR2やCHARへ変換しているためです。SQL上の文字列型には上限があるため、CLOBを丸ごと変換するとORA-22835になります。
DBMS_LOB.SUBSTRで4000より大きく取れますか?
PL/SQLではより大きなVARCHAR2を扱える場面がありますが、SQL上では4000バイト上限に当たりやすいです。環境と実行場所により上限が変わるため、全量が必要なら分割読み出しを検討します。
MAX_STRING_SIZE=EXTENDEDで解決しますか?
上限が広がるケースはありますが、数万バイトを超えるCLOBでは根本解決になりません。CLOBをCLOBのまま扱う設計にする方が安全です。
まとめ
ORA-22835は、CLOBをCHAR/VARCHAR2へ、またはBLOBをRAWへ変換する時に、変換先バッファの上限を超えると発生します。CLOBやBLOBの容量ではなく、変換先の型の上限が原因です。
短い表示なら DBMS_LOB.SUBSTR、全量処理ならCLOB/BLOBのまま扱うか分割読み出しにします。TO_CHAR(CLOB) や暗黙的なVARCHAR2変換を避けることが、再発防止の基本です。

