- PR -

PL/SQLでOPEN CURSORとCLOSE CURSORを別々のストアドから行いたい

投稿者投稿内容
kernel
常連さん
会議室デビュー日: 2005/10/05
投稿数: 22
投稿日時: 2006-08-30 19:02
PL/SQLの質問です。

あるストアドでOPENしたCURSORを、別のストアドでCLOSEする
ということができますでしょうか?

通常は、OPEN CURSOR名、CLOSE CURSOR名でCURSORをOPEN/CLOSE
すると思います(少なくとも自分は)

これを例えば、OPENした時にセッションごとに固有のIDを取得
して、ストアドを呼んだアプリに返し、次にアプリからIDを指
定してCLOSEするというのは可能ですか?

ORCLEのバージョンは9i。ストアドをコールするアプリはC#です。
saki1208
ベテラン
会議室デビュー日: 2006/08/22
投稿数: 86
投稿日時: 2006-08-30 20:11

saki1208です。

なぜ?そのようなことが必要なのかはわかりませんが...

ストアド・パッケージ使用すれば可能ではないでしょうか?
(実際に試した訳ではないので、間違っていたらごめんなさいですが)

ストアド・パッケージの仕様部で宣言されたカーソル、変数などは
同一セッション上でその内容を保持しています。


kernel
常連さん
会議室デビュー日: 2005/10/05
投稿数: 22
投稿日時: 2006-09-05 17:51
saki1208さん、ありがとうございます。

返答が遅れてしまいまして、申し訳ありません。

今、C#からPL/SQLをコールして、結果をOracleDataReaderで
受け取る処理を作っています。

ところ、カーソルを閉じるメソッドがわからず困っています。
※CloseやDisposeがそれかと思ったのですが、ダメでした。
※MSDNで見てもCloseで終わっていました。

カーソルが閉じないため、数百回同じPL/SQLをコールすると
「最大オープン・カーソル数を超えました」とエラーになり、
OracleDataReaderのインスタンスを作る処理で、
「文の処理が実行されません」とエラーになります。

それで、あのような質問をさせていただきました。
saki1208
ベテラン
会議室デビュー日: 2006/08/22
投稿数: 86
投稿日時: 2006-09-05 18:32

saki1208です。

出力されているメッセージからすると...
Oracleのエラーだと思います。

また、該当のエラーは、PL/SQL内でカーソルを閉じずに
Openを繰り返した場合に出力されるエラーです。
※これは、マニュアルを参照すればわかると思います。
 マニュアルは、Oracleのインストール媒体に含まれて
 いますし、OTNからダウンロードすることも可能です。

最初の返信にて記述させていただいた通り、ストアド・
パッケージの仕様部で宣言されたカーソル、変数などは
同一セッション上でその内容を保持しています。

PL/SQL上でカーソルのクローズを行わずに、OPENのみを
繰り返し実行されているのではないでしょうか?
エラーが発生しないようにするためには、結果をOracle
DataReaderで受け取った後に、PL/SQL上でカーソルをク
ローズしてあげる必要があるはずですが、クロースされ
ていますか?
kernel
常連さん
会議室デビュー日: 2005/10/05
投稿数: 22
投稿日時: 2006-09-06 15:07
>>Openを繰り返した場合に出力されるエラーです。
そこまではわかっているのですが、Closeの仕方がわからないのです。

C#のソースは↓のような感じです。
OracleCommand oracmd = db.OpenCmd("カーソルを開くPL/SQL");

oracmd.CommandType = CommandType.StoredProcedure;

oracmd.ExecuteNonQuery();

OracleDataReader oradatr = oracmd.ExecuteReader();

while(oradatr.Read())
{}
oradatr.Close(); <---カーソルが閉じない

PL/SQLは↓のような感じです。
---仕様部
TYPE CUR_TYPE IS REF CURSOR;
FUNCTION OpenCur(P_CUR OUT CUR_TYPE) RETURN NUMBER;

---実行部
FUNCTION OpenCur(P_CUR OUT CUR_TYPE) RETURN NUMBER
IS
BEGIN

OPEN P_CUR FOR SELECT * FROM テーブル

RETURN 0;

END OpenCur;

saki1208さんは、FUNCTION内部でCLOSE P_CURをやれと
言われてると思いますが、それをやるとC#側でフェッチ
できないのです。

そこで、OpenCurというFunctionでOpenしたカーソルを
CloseCurなど別のFunctionでCloseできないか?ということを
聞きたかったのです。説明不足ですいません。
もしもし
ぬし
会議室デビュー日: 2004/10/15
投稿数: 280
投稿日時: 2006-09-07 11:45
function の出力を、カーソルそのものじゃなくて PL/SQL 表とかに
変更したら対応できないでしょうかね。

(function の出力結果がカーソルそのものだったら、カーソルは
閉じようがないのでは、と思ってみたり)

_________________
もしもし@RMAN 友の会
99ri
大ベテラン
会議室デビュー日: 2006/09/09
投稿数: 129
投稿日時: 2006-09-09 09:23
OracleのODP.NETには
OracleParameterクラスにDispose()があります

OUTパラメータのREFCURSORをDisposeすることで
コネクションをクローズしなくてもカーソルがクローズされると思います
*オラクルのサイトにサンプルがあります

REFCURSORについて
 msdn2.microsoft.com/ja-jp/library/bw9eczdk.aspx
入力パラメータとしての REF CURSOR はサポートしていません。

 とあるので
 カーソルをクローズするプロシージャに引数としてわたせません

パッケージでREF CURSOR変数を保持する案
 PLS-00994: カーソル変数をパッケージの一部として宣言できません。
 のエラーになります
 同一セッションで使用する変数にREF CURSORは使用できないようです

なのでOracleのODP.NETをためされてはいかがでしょうか?
v$open_cursorで結果(カーソルクローズの有無)を確認できます
99ri
大ベテラン
会議室デビュー日: 2006/09/09
投稿数: 129
投稿日時: 2006-09-09 17:20
引用:

未記入さんの書き込み (2006-09-09 09:23) より:
OracleのODP.NETには

OUTパラメータのREFCURSORをDisposeすることで
コネクションをクローズしなくてもカーソルがクローズされると思います



Dispose()でカーソルクローズするのではないようです

OracleRefCursorクラス経由でとりだしを行うと

oracmd.ExecuteNonQuery();
OracleDataReader reader1 = ((OracleRefCursor)p1.Value).GetDataReader();
reader1.Close();

で最後に発行したSQLのみv$open_cursorに表示されました 環境は10gです

スキルアップ/キャリアアップ(JOB@IT)