DABroker for C++

[目次][用語][索引][前へ][次へ]

2.6.6 ストアドプロシジャの利用

ストアドプロシジャを利用するには,データベースの接続時に生成したDBConnectionオブジェクトのCreateCallableStatementメソッドを呼び出し,DBCallableStatementオブジェクトを生成します。次に,SetProcedureメソッドで実行するストアドプロシジャ名を指定し,引数をSetParamメソッドで設定し,Executeメソッドで実行します。

戻り値のあるストアドプロシジャの実行結果は, GetParamメソッドの引数で受け取る方法と,ResultSetで受け取る方法があります。また,これらを併用することもできます。

ストアドプロシジャは,サーバ系の下記DBMSで利用可能でであり,ストアドプロシジャを利用するには,DBCallableStatementクラスを使います。

<この項の構成>
(1) ストアドプロシジャの実行
(2) ストアドプロシジャの戻り値の受け取り(引数)
(3) ストアドプロシジャの戻り値の受け取り(ResultSet)

(1) ストアドプロシジャの実行

ストアドプロシジャを利用するには,データベースの接続時に生成したDBConnectionオブジェクトのCreateCallableStatementメソッドを呼び出し,DBCallableStatementオブジェクトを生成します。次に,SetProcedureメソッドで実行するストアドプロシジャ名を指定し,引数をSetParamメソッドで設定し,Executeメソッドで実行します。

 
DBConnection*         pConnect;
  DBCallableStatement*  pCall;
  {
    // DBCallableStatementオブジェクトの生成
    pCall = pConnect->CreateCallableStatement("sample1");
    pCall->SetProcedure("Proc100");               // プロシジャ名設定
    pCall->Execute();                             // プロシジャ実行
  }
(a) 引数を持つストアドプロシジャの実行

ストアドプロシジャが引数を持つ場合,SetProcedureメソッドでは,プロシジャ名に続けて"?"を引数分指定します。?パラメタに設定する値は,DBCallableStatementオブジェクトのSetParamメソッドで指定します。SetParamメソッドでは,?パラメタの位置と設定するデータを指定します。

SetParamメソッドで指定する?パラメタの位置は,IN,INOUTパラメタの位置です。OUTは含みません。

 
  DBConnection*         pConnect;
  DBCallableStatement* pCall;
 {
    // DBCallableStatementオブジェクト生成
    pCall = pConnect->CreateCallableStatement("sample1");
    pCall->SetProcedure("Proc_100(?,?)");
                                        // ストアドプロシジャ名設定
    pCall->SetParam(1, pszCity) ;      // パラメタ値の設定
    pCall->Execute();                   // ストアドプロシジャ実行
 }
(b) 同期・非同期処理

ストアドプロシジャも通常のデータベースアクセスと同様,DBConnectionオブジェクトの設定により同期・非同期処理が行われます。

 
  DBConnection*         pConnect;
  DBCallableStatement* pCall;
  {
    // DBCallableStatementオブジェクトの生成
    pCall = pConnect->CreateCallableStatement("sample1");
    pCall->SetProcedure("Proc_100");         // プロシジャ名設定
    pCall->Execute();                        // プロシジャ実行
    pCall->WaitForDataSource(DBR_INFINITE);
                                       // プロシジャ実行完了待ち
}

また,ストアドプロシジャの実行完了確認には,DBCallableStatementオブジェクトのIsCompletedメソッドも使えます。

 
    if (!pCall->IsCompleted())             // プロシジャ実行の完了確認
    pResultSet = pCall ->GetResultSet();   // 検索結果の受け取り

(2) ストアドプロシジャの戻り値の受け取り(引数)

この項では,戻り値のあるストアドプロシジャの実行結果を,引数で受け取る方法について説明します。

実行結果は DBCallableStatementオブジェクトのGetParamメソッドの引数で受け取ります。データはGetparamメソッドの引数で指定したデータ型で取得します。

 
void class1::func1(char* pszCity,INT32 dwCount)
 {
  DBConnection*           pConnect;
  DBCallableStatement*   pCall;
 
            // DBCallableStatementオブジェクトの生成
    pCall = pConnect->CreateCallableStatement("sample1");
    pCall->SetProcedure("Proc_100(?,?)");
                                      // ストアドプロシジャ名設定
    pCall->SetParam(1, pszCity) ;    // パラメタ値の設定
    pCall->Execute();                 // ストアドプロシジャ実行
    pCall->WaitForDataSource(DBR_INFINITE);
                                      // プロシジャ実行完了待ち
    pCall->GetParam(1, &dwCount);    // 戻り値の受け取り
}

なお,INパラメタとOUTパラメタの位置はどちらも1になります。

(3) ストアドプロシジャの戻り値の受け取り(ResultSet)

下記DBMSの場合だけ,ストアドプロシジャでのSELECT文の実行結果が複数のレコードでもアプリケーションで受け取ることができます。

この場合,ストアドプロシジャではRESULT句で戻り値の型を定義し,アプリケーションでは,DBResultSetクラスのResultSetとして受取り,GetFieldメソッドで参照します。

(a) ストアドプロシジャの形式

ストアドプロシジャでは,SELECT文の結果を呼び出し元に渡すために,RESULT句で戻り値の型を定義します。

CREATE PROCEDURE sample ()
RESULT ("Value" INT,"Shop" CHAR(30))
BEGIN
  SELECT  CAST( sum( sales_order_items.quantity *
                product.unit_price)
                AS INTEGER ) AS value
                shop_name, 
  FROM customer
           INNER JOIN sales_order 
           INNER JOIN sales_order_items 
           INNER JOIN product 
  GROUP BY shop_name 
  ORDER BY value desc;
END

この例では,value及びshop_nameの検索結果をResultSetとして扱うために,RESULT句でValue及びShopフィールドとそのデータ型を新しく定義しています。

また,SELECT文中に演算処理がある場合は,その結果を考慮してストアドプロシジャの作成時に,結果に合ったデータ型をRESULT句で用意しておきます。

なお,RESULT句に指定するデータ型は,元テーブルと同じデータ型,又は自動的に変換できるデータ型だけが指定できます。自動変換できるデータ型については,使用するDBMSのドキュメントを参照してください。

(b) ResultSetの参照

ストアドプロシジャの検索結果をResultSetで受け取る場合,DBCallableStatementオブジェクトからGetResultSetメソッドを呼び出して,DBResultSetオブジェクトを生成し,検索結果をResultSetに得ます。ResultSetに読込まれたレコードを参照する方法については,「2.5.2検索レコードの参照」と同様です。

データの型
ストアドプロシジャ内のRESULT句で定義したデータ型とGetFieldメソッドの引数に指定したデータ型とが異なる場合は,引数のデータ型に合わせて変換されます。データ変換については,「7.1 クラスライブラリで扱うデータ型と変換規則」を,変換時の注意事項については「2.5.2 検索レコードの参照」を参照してください。

データ変換
ストアドプロシジャ内のSELECT文の場合も単純なSELECT文の場合も,検索結果をDBResultSetクラスのGetFieldメソッドで参照します。異なる点は,単純なSELECT文の場合データベースでのフィールドの型をGetFieldメソッドの引数に指定したデータ型に変換して参照しますが,ストアドプロシジャの場合RESULT句で定義したフィールドの型をGetFieldメソッドの引数に指定したデータ型に変換して参照します。

その他
ストアドプロシジャを利用した検索でのレコードのロック方法は,SetResultSetTypeメソッドの引数で設定します。
また,検索結果が複数レコードの場合,n件ずつ分割して取得することもできます。このとき一度に取得するレコードの最大数は,SetMaxRowsメソッドで指定します。
(c) 複数ResultSetの参照

ストアドプロシジャ中に,SELECT文が複数記述されているストアドプロシジャでは,SELECT文ごとにResultSetを扱います。

次に,複数のSELECT文を記述したストアドプロシジャの例を示します。

 
CREATE PROCEDURE ListPeople()
RESULT ( lname CHAR(36), fname CHAR(36) )
BEGIN
	SELECT emp_lname, emp_fname FROM employee;
	SELECT lname, fname FROM customer;
	SELECT last_name, first_name FROM contact;
END

SELECT文ごとにResultSetを返すストアドプロシジャも,RESULT句を指定します。ただし,複数のSELECT文があっても,プロシジャ中にRESULT句は一つだけしか指定できません。このため,指定するSELECT文には次のような制限があります。

アプリケーションでは,これらの制限によって,RESULT句だけを意識すればよくなります。つまり,GetFieldメソッドを使ってアプリケーションから参照する時は,RESULT句で定義したフィールドのデータ型だけを意識します。

プロシジャ内の次のSELECT文に対するResultSetを取得する概念図を図2-4に示します。

図2-4 プロシジャ内の次のSELECT文に対するResultSetを取得する概念図

[図データ]

検索結果の有無確認
複数のSELECT文がある場合,ひとつのResultSetの参照が終わっても,次のResultSetの処理が必要となります。このような場合,IsEOFメソッドとIsCompletedメソッドを利用して判断します。
下記例は,ResultSetの有無をIsCompletedメソッドで確認し,ResultSet中のレコードの確認をIsEOFメソッドで確認しています。
    pCall->Execute();                  // ストアドプロシジャ実行
    if (!pCall->IsCompleted())         // プロシジャ実行の完了確認
    {
        pResultSet = pCall ->GetResultSet(); // 検索結果の受け取り
        while(!pResultSet->IsEOF())
        {
            pResultSet->GetField(1, &nField);      // データの取得
            cout << "  Data=" << nField;
            pResultSet->GetField(2, &pField);
            cout << "  Data=" << pField;
            cout << endl;
            pResultSet->Next();          // 次のレコードの読み込み
        }
        pCall->Resume();                 // 処理の継続
    }
GetResultSetメソッドを実行すると,前に作成したDBResultSetオブジェクトは削除されることに注意してください。

カーソルの移動
複数のSELECT文がある場合,ひとつのResultSetに対する処理が終了した後で,Resumeメソッドを使って,カーソルを以降のResultSetの先頭に位置付ける必要があります。