ページの先頭行へ戻る
Enterprise Postgres 12 アプリケーション開発ガイド
FUJITSU Software

B.7.1 カーソルを使って検索したい

Oracleデータベース

CREATE PROCEDURE search_test(h_where CLOB) AS


    str_sql     CLOB;
    v_cnt       INTEGER;
    v_array     DBMS_SQL.VARCHAR2A;
    v_cur       INTEGER;
    v_smpid     INTEGER;
    v_smpnm     VARCHAR2(20);
    v_addbuff   VARCHAR2(20);
    v_smpage    INTEGER;
    errcd       INTEGER;
    length      INTEGER;
    ret         INTEGER;
BEGIN

    str_sql     := 'SELECT smpid, smpnm FROM smp_tbl WHERE ' || h_where || ' ORDER BY smpid';
    v_smpid     := 0;
    v_smpnm     := '';
    v_smpage    := 0;

    v_cur := DBMS_SQL.OPEN_CURSOR;・・・(1)

    v_cnt := 
      CEIL(DBMS_LOB.GETLENGTH(str_sql)/1000); 
    FOR idx IN 1 .. v_cnt LOOP
        v_array(idx) := 
            DBMS_LOB.SUBSTR(str_sql,
                            1000,
                            (idx-1)*1000+1); 
    END LOOP;
    DBMS_SQL.PARSE(v_cur, v_array, 1, v_cnt, FALSE, DBMS_SQL.NATIVE);・・・(2)

    DBMS_SQL.DEFINE_COLUMN(v_cur, 1, v_smpid);

    DBMS_SQL.DEFINE_COLUMN(v_cur, 2, v_smpnm, 10);


    ret := DBMS_SQL.EXECUTE(v_cur);
    LOOP
        v_addbuff := '';

        IF DBMS_SQL.FETCH_ROWS(v_cur) = 0 THEN
            EXIT;
        END IF;

        DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------');
        DBMS_SQL.COLUMN_VALUE(v_cur, 1, v_smpid, errcd, length);・・・(3)




        IF errcd = 1405 THEN・・・(3)

          DBMS_OUTPUT.PUT_LINE('smpid       = (NULL)');
        ELSE
          DBMS_OUTPUT.PUT_LINE('smpid       = ' || v_smpid);
        END IF;

        DBMS_SQL.COLUMN_VALUE(v_cur, 2, v_smpnm, errcd, length);

        IF errcd = 1406 THEN
          v_addbuff := '... [len=' || length || ']';
        END IF;
        IF errcd = 1405 THEN
          DBMS_OUTPUT.PUT_LINE('v_smpnm     = (NULL)');
        ELSE
          DBMS_OUTPUT.PUT_LINE('v_smpnm     = ' || v_smpnm || v_addbuff );
        END IF;

DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------');

        DBMS_OUTPUT.NEW_LINE;
    END LOOP;

    DBMS_SQL.CLOSE_CURSOR(v_cur);・・・(4)

    RETURN;
END;
/

Set serveroutput on

call search_test('smpid < 100');

FUJITSU Enterprise Postgres

CREATE FUNCTION search_test(h_where text) RETURNS void AS $$
DECLARE
    str_sql     text;


    v_cur       INTEGER;
    v_smpid     INTEGER;
    v_smpnm     VARCHAR(20);
    v_addbuff   VARCHAR(20);
    v_smpage    INTEGER;
    errcd       INTEGER;
    length      INTEGER;
    ret         INTEGER;
BEGIN
    PERFORM DBMS_OUTPUT.SERVEROUTPUT(TRUE);
    str_sql     := 'SELECT smpid, smpnm FROM smp_tbl WHERE ' || h_where || ' ORDER BY smpid';
    v_smpid     := 0;
    v_smpnm     := '';
    v_smpage    := 0;

    v_cur := DBMS_SQL.OPEN_CURSOR();・・・(1)

    PERFORM DBMS_SQL.PARSE(v_cur, str_sql, 1);・・・(2)
    PERFORM DBMS_SQL.DEFINE_COLUMN(v_cur, 1, v_smpid);
    PERFORM DBMS_SQL.DEFINE_COLUMN(v_cur, 2, v_smpnm, 10);
   
    ret := DBMS_SQL.EXECUTE(v_cur);
    LOOP
        v_addbuff := '';

        IF DBMS_SQL.FETCH_ROWS(v_cur) = 0 THEN
            EXIT;
        END IF;

        PERFORM DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------');
        SELECT value,column_error,actual_length
          INTO v_smpid, errcd, length 
          FROM DBMS_SQL.COLUMN_VALUE(v_cur,
                                     1,
                                     v_smpid);・・・(3)
        IF errcd = 22002 THEN・・・(3)
          PERFORM DBMS_OUTPUT.PUT_LINE('smpid       = (NULL)');
        ELSE
          PERFORM DBMS_OUTPUT.PUT_LINE('smpid       = ' || v_smpid);
        END IF;

        SELECT value,column_error,actual_length INTO v_smpnm, errcd, length FROM DBMS_SQL.COLUMN_VALUE(v_cur, 2, v_smpnm);
        IF errcd = 22001 THEN
          v_addbuff := '... [len=' || length || ']';
        END IF;
        IF errcd = 22002 THEN
          PERFORM DBMS_OUTPUT.PUT_LINE('v_smpnm     = (NULL)');
        ELSE
          PERFORM DBMS_OUTPUT.PUT_LINE('v_smpnm     = ' || v_smpnm || v_addbuff );
        END IF;

        PERFORM DBMS_OUTPUT.PUT_LINE('--------------------------------------------------------');
        PERFORM DBMS_OUTPUT.NEW_LINE();
    END LOOP;

    v_cur := DBMS_SQL.CLOSE_CURSOR(v_cur);・・・(4)
    RETURN;
END;
$$
LANGUAGE plpgsql;


SELECT search_test('smpid < 100');

(1) OPEN_CURSOR

DBMS_OUTPUTパッケージのNEW_LINEと同じです。記述差異および、記述差異に伴う移行手順については、DBMS_OUTPUTパッケージのNEW_LINEを参照してください。


(2) PARSE
Oracleデータベースにおける記述形式

DBMS_SQL.PARSE(第1引数, 第2引数, 第3引数, 第4引数, 第5引数, 第6引数)

機能差異
Oracleデータベース

SQL文を文字列の表タイプ(VARCHAR2A型、VARCHAR2S型)で指定することができます。これは、第2引数に指定します。

SQL文を処理する方法の指定にDBMS_SQL.NATIVE、DBMS_SQL.V6、DBMS_SQL.V7を指定することができます。

FUJITSU Enterprise Postgres

SQL文を文字列の表タイプでは指定できません。

SQL文を処理する方法の指定にDBMS_SQL.NATIVE、DBMS_SQL.V6、DBMS_SQL.V7を指定することができません。

移行手順

以下の手順で移行してください。

  1. “DBMS_SQL.PARSE”というキーワードでストアドプロシジャ内を検索し、呼び出し箇所を特定します。

  2. 第2引数(例のv_array)に指定されたSQL文のデータ型を確認します。

    • データ型がDBMS_SQL.VARCHAR2A型、またはDBMS_SQL.VARCHAR2S型である場合は、表タイプによる指定です。3.の手順から移行処理を継続してください。

    • データ型がDBMS_SQL.VARCHAR2A型、またはDBMS_SQL.VARCHAR2S型でない場合は、文字列による指定です。7.の手順から移行処理を継続してください。

  3. DBMS_SQL.VARCHAR2A型、およびDBMS_SQL.VARCHAR2S型に分割する前のSQL文(例のstr_sql)を確認します。

  4. DBMS_SQL.VARCHAR2A型、およびDBMS_SQL.VARCHAR2S型にSQLを分割している一連の処理(例のFOR idx付近の処理)を削除します。

  5. 第2引数を2.で確認した分割する前のSQL文(例のstr_sql)に置き換えます。

  6. 第3引数~第5引数(例のv_cnt, FALSE, DBMS_SQL.NATIVE)までを削除します。

  7. DBMS_SQL.NATIVE、DBMS_SQL.V6、DBMS_SQL.V7が指定されている場合は、第3引数を数定数 1 に置き換えます。

    • DBMS_SQL.VARCHAR2A型、またはDBMS_SQL.VARCHAR2S型を使用している場合は第6引数が該当します。

    • DBMS_SQL.VARCHAR2A型、またはDBMS_SQL.VARCHAR2S型を使用していない場合は第3引数が該当します。


(3) COLUMN_VALUE
Oracleデータベースにおける記述形式

DBMS_SQL.COLUMN_VALUE(第1引数, 第2引数, 第3引数, 第4引数, 第5引数)

機能差異
Oracleデータベース

column_errorに対して以下のエラーコードを戻します。

  • 1406 : 取得した値が切り捨てられている

  • 1405 : 取得した値の内容がNULL値

FUJITSU Enterprise Postgres

column_errorに対して以下のエラーコードを戻します。

  • 22001 : 取得した値が切り捨てられている

  • 22002 : 取得した値の内容がNULL値

記述差異
Oracleデータベース

取得する値は、引数に指定した変数で受け取ります。

FUJITSU Enterprise Postgres

取得する値は、DBMS_SQL.COLUMN_VALUEの検索結果なので、SELECT文のINTO句に指定した変数で受け取ります。

移行手順

以下の手順で移行してください。

  1. “DBMS_SQL.COLUMN_VALUE”というキーワードでストアドプロシジャ内を検索し、呼び出し箇所を特定します。

  2. DBMS_SQL.COLUMN_VALUEの呼び出し箇所を、SELECT INTO文に置き換えます。

    • DBMS_SQL.COLUMN_VALUEの第3引数(例のv_smpid)以降に指定している引数の数を確認します(例の場合は、v_smpid, errcd, length の3個)。

    • 選択リストに、先で確認した引数の数に応じてそれぞれvalue、column_error、actual_lengthの順で指定します。(例えば、第3引数のみ指定されている場合はvalueのみを指定します)

    • INTO句に、DBMS_SQL.COLUMN_VALUEに設定していた第3引数~第5引数(例のv_smpid, errcd, length)を同じ順番で指定します。

    • FROM句にDBMS_SQL.COLUMN_VALUEを記載します。引数は修正前の第1引数~第3引数(例のv_cur, 1, v_smpid)までを指定します。

  3. 第4引数(例のcolumn_errorの値)を使用している場合は、対象の変数(例のerrcd)を使用している箇所を確認します。

  4. 確認した箇所で判定などの処理を行っている場合は、判定する際の値を以下の通り修正します。

    • 1406 ⇒ 22001

    • 1405 ⇒ 22002


(4) CLOSE_CURSOR
Oracleデータベースにおける記述形式

DBMS_SQL.CLOSE_CURSOR(第1引数)

記述差異
Oracleデータベース

クローズすると、引数に指定したカーソルがNULL値になります。

FUJITSU Enterprise Postgres

クローズすると、DBMS_SQL.CLOSE_CURSORの復帰値がNULL値になりますので、代入文に指定したカーソルで受け取ります。

移行手順

以下の手順で移行してください。

  1. “DBMS_SQL.CLOSE_CURSOR”というキーワードでストアドプロシジャ内を検索し、呼び出し箇所を特定します。

  2. DBMS_SQL.CLOSE_CURSORの呼び出し箇所を、値の代入(:=)に置き換え、カーソルがNULL値となるようにします。

    • 左辺にDBMS_SQL.CLOSE_CURSORに指定していた引数(例のv_cur)を指定します。

    • 右辺にDBMS_SQL.CLOSE_CURSORを記載します。引数は修正前と同じ値(例のv_cur)を指定します。