ストアドプロシジャを利用するには,データベースの接続時に生成したDBConnectionオブジェクトのCreateCallableStatementメソッドを呼び出し,DBCallableStatementオブジェクトを生成します。次に,SetProcedureメソッドで実行するストアドプロシジャ名を指定し,引数をSetParamメソッドで設定し,Executeメソッドで実行します。
戻り値のあるストアドプロシジャの実行結果は, GetParamメソッドの引数で受け取る方法と,ResultSetで受け取る方法があります。また,これらを併用することもできます。
ストアドプロシジャは,サーバ系の下記DBMSで利用可能でであり,ストアドプロシジャを利用するには,DBCallableStatementクラスを使います。
ストアドプロシジャを利用するには,データベースの接続時に生成したDBConnectionオブジェクトのCreateCallableStatementメソッドを呼び出し,DBCallableStatementオブジェクトを生成します。次に,SetProcedureメソッドで実行するストアドプロシジャ名を指定し,引数をSetParamメソッドで設定し,Executeメソッドで実行します。
DBConnection* pConnect;
DBCallableStatement* pCall;
{
// DBCallableStatementオブジェクトの生成
pCall = pConnect->CreateCallableStatement("sample1");
pCall->SetProcedure("Proc100"); // プロシジャ名設定
pCall->Execute(); // プロシジャ実行
}
ストアドプロシジャが引数を持つ場合,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(); // ストアドプロシジャ実行
}
ストアドプロシジャも通常のデータベースアクセスと同様,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(); // 検索結果の受け取り
この項では,戻り値のあるストアドプロシジャの実行結果を,引数で受け取る方法について説明します。
実行結果は 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になります。
下記DBMSの場合だけ,ストアドプロシジャでのSELECT文の実行結果が複数のレコードでもアプリケーションで受け取ることができます。
この場合,ストアドプロシジャではRESULT句で戻り値の型を定義し,アプリケーションでは,DBResultSetクラスのResultSetとして受取り,GetFieldメソッドで参照します。
ストアドプロシジャでは,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のドキュメントを参照してください。
ストアドプロシジャの検索結果をResultSetで受け取る場合,DBCallableStatementオブジェクトからGetResultSetメソッドを呼び出して,DBResultSetオブジェクトを生成し,検索結果をResultSetに得ます。ResultSetに読込まれたレコードを参照する方法については,「2.5.2検索レコードの参照」と同様です。
ストアドプロシジャ中に,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を取得する概念図
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(); // 処理の継続
}