2022年4月27日水曜日

レポートの行の文字数制限について

 レポートに表示される行のデータが長いとORA-6502が発生する、との相談がありました。Oracle APEXはデータベース・サーバーでHTMLを生成しています。その処理はPL/SQLで記述されていますが、PL/SQLのVARCHAR2の最大値が32767バイトであるため、いくつかの箇所で、32767バイトが扱えるデータの上限になっています。

クラシック・レポートと対話モード・レポートの1行の長さも、そのひとつです。

以下のようなエラーが発生します。

同じレポートでも対話グリッドは、ブラウザ側でJavaScriptのコンポーネントとして実装されていて、描画(HTMLの生成)はブラウザ側で行われています。そのため、このような制限はありません。

クラシック・レポートを例にとって、1行の長さがどのように決まるのか説明します。クラシック・レポートのテンプレートを新規に作成する、または編集するときの参考になると思います。

最初にテストに使用するデータを準備します。

表TEST_STRLENを作成し、1バイトから32767バイトまでの長さの文字列を挿入します。

create table test_strlen(str varchar2(32767));

declare
    l_string varchar2(32767);
begin
    for i in 1..32767
    loop
        l_string := l_string || mod(i,10);
        insert into test_strlen values(l_string);
    end loop;
end;

確認作業にはAlways FreeのAutonomous Databaseを使用しています。ADBは初期化パラメータのMAX_STRING_SIZEEXTENDEDになっているため、VARCHAR2の最大サイズが32767バイトになっています。そうでない場合は4000バイトが上限になるため、代わりに最大サイズの制限がないCLOBを使う必要があります。

作成した表TEST_STRLENには、1バイトから32767バイトまでの長さの文字列が挿入されています。全部で32767行になります。

確認に使用するAPEXアプリケーションを作成します。

アプリケーション作成ウィザードを起動します。

アプリケーションの名前文字数制限の確認とします。ページの追加をクリックし、クラシック・レポートのページを作成します。

追加ページを開いて、クラシック・レポートを選択します。

ページ名レポートとし、SQL問合せとして、以下のSQLを記述します。

select str
from test_strlen
where length(str) <= :P1_MAX
order by length(str) desc

検索条件に使用しているページ・アイテムP1_MAXは、アプリケーションの作成後に追加します。

ホーム・ページは使わないので編集をクリックして、削除を実行します。レポートのページだけを含めて、アプリケーションの作成を実行します。

アプリケーションが作成されたら、ページ・デザイナホーム・ページを開きます。リージョンレポートにページ・アイテムP1_MAXを作成します。

識別名前P1_MAX、タイプを数値フィールドラベル最大値とします。


以上で確認に使用するアプリケーションは完成です。

アプリケーションを実行し、表示できる文字数の上限を確認します。

エラーが発生せずにレポートが表示される上限は、32693バイトでした。32767バイトまでは扱えません。


クラシック・レポートでは、レポートの1行がどのように表示されるかは、レポートテンプレートで決められています。

使用しているテンプレートは、リージョンAttributes外観テンプレートにて、設定されています。今回の例ではStandardを使用しています。


レポート・テンプレートのStandardを確認します。

左ペインで共有コンポーネント・ビューを開き、テンプレート以下のクラシック・レポートに含まれるStandardを選択します。右ペインでコンポーネントの編集をクリックします。


テンプレートStandardの編集画面が開きます。


レポートのテンプレートに、各行の前<tr>と設定されています。


列テンプレートの設定は以下です。ここで#COLUMN_VALUE#がSQLの検索結果に置き換えられます。

<td class="t-Report-cell" #ALIGNMENT# headers="#COLUMN_HEADER_NAME#">#COLUMN_VALUE#</td>


各行の後</tr>です。


レポートの1行の長さ(バイト数)は、テンプレートに含まれている置換文字列が置き換えられた後の、以下の合計の長さになります。

各行の前 + 列テンプレート(複数の列がある場合は繰り返し) + 各行の後

列テンプレートをもっと簡単にして、上限を確認してみます。テンプレートStandardを編集します。標準のテンプレートを直接編集すると他のレポートに影響するため、コピーを作成して編集します。

共有コンポーネントテンプレートを開き、レポート・テンプレートStandardコピーします。


新規テンプレート名Standard-Simple新規テンプレート識別子STANDARD-SIMPLEとして、コピーを実行します。


レポート・テンプレートStandardのコピーがStandard-Simpleとして作成されます。Standard-Simpleを開いて、列テンプレートを変更します。


列テンプレートを以下に変更します。

<td>#COLUMN_VALUE#</td>

変更の適用をクリックします。


このテンプレートでは、1行の表示は以下になります。

<tr><td>#COLUMN_VALUE#</td></tr>

HTMLのタグは18バイトになるので、列のデータとしては32767 - 18 = 32749が上限になります。

実際にアプリケーションで確認してみます。クラシック・レポートのテンプレートStandard-Simpleに変更します。


アプリケーションを実行し、最大値32749を入力します。レポートは正常に表示されます。


最大値として32750を指定すると、エラーが発生します。


レポートの表示の仕組みと、1行の長さの上限値の説明は以上になります。

対話モード・レポートでも表示の仕組みは同様で、1行の上限値についても同様に適用されます。

Oracle APEXのアプリケーション作成の参考になれば幸いです。