Visual StudioからのOracle PL/SQLのデバッグ

このチュートリアルでは、Visual StudioからOracle PL/SQLをデバッグする方法について説明します。

約30分

このチュートリアルでは、以下のトピックについて説明します。

このアイコンの上にカーソルを置くと、このチュートリアルのすべてのスクリーンショットがロードされて、表示されます。 (警告: すべてのスクリーンショットが同時にロードされるため、ご使用のインターネット接続によってはレスポンス・タイムが遅くなる場合があります。)

注: 各手順に関連したスクリーンショットのみをロードして表示する場合は、それぞれの手順にあるアイコンの上にカーソルを置いてください。 個々のスクリーンショットはクリックすると、非表示になります。

ODT 10.2.0.2の新たに統合されたPL/SQLデバッガを使用すると、Visual Studioを終了せずに、.NETおよびOracleソリューションのエンドツーエンド・デバッグを行うことができます。 プロシージャとファンクション(スタンドアロンおよびパッケージ済みの両方)、オブジェクト・メソッド、およびトリガーなどのPL/SQLコードを、Visual Studio環境内からC#またはVB.NETコードをデバッグするのと同じ方法でデバッグできます。 ODTに統合されたPL/SQLデバッガでは、ブレーク・ポイントの設定、変数値の表示と変更、およびコール・スタックの検査などの従来のデバッグ機能を使用できます。

PL/SQLデバッガは、次の3つのモードのいずれかで使用します。

Direct Database Debugging Direct Database Debuggingモードでは、Visual Studio環境から直接PL/SQLコードをデバッグできます。 Direct Database Debuggingモードを使用する場合、Visual Studioソリューションや.NETコードは必要ありません。データベース内のPL/SQLコードを直接取り扱うことができます。 Oracle Explorerでプロシージャまたはファンクションを右クリックすることで、PL/SQLプロシージャまたはファンクションに移動したり、設定したブレーク・ポイントまで実行したりできます。 当然、PL/SQLコードに引数を渡したり、PL/SQLコードからの戻り値を受け取ったりすることもできます。
External Application Debugging Visual Studio以外で実行しているアプリケーション(Windows以外のプラットフォームで実行しているアプリケーションなど)によってコールされるPL/SQLコードをデバッグする必要がある場合は、External Application Debuggingモードを使用します。 このモードでは、任意のプラットフォームにある(Oracleクライアント・ライブラリ9.2以降で構築された)任意のアプリケーションによってコールされるPL/SQLプログラムを、アプリケーションを変更することなくデバッグできます。 このモードは、中間層にあるASP.NETアプリケーションのデバッグでもっとも頻繁に使用されます。
Multi-tier Application Debugging .NETアプリケーションの開発時におけるもっとも強力なオプションは、Multi-Tier Application Debuggingモードです。 このモードでは、Visual Studioソリューション内から.NETコードおよびPL/SQLコードの両方をシームレスにデバッグできます。 .NETコードから直接PL/SQLコードに移動して、再び戻ることができます。

このチュートリアルでは、Multi-tier Application Debuggingモードを使用します。 このモードでは、開発者は、デバッグ・セッション中に.NETコードとPL/SQLコードを同時に取り扱うことができます。

アプリケーションの作成を開始する前に、Visual Studioを起動して接続を作成します。 以下の手順を実行します。

1.

スタート」→「すべてのプログラム」→「Microsoft Visual Studio 2005」→「Microsoft Visual Studio 2005」を選択します。

 

2.

View」→「Server Explorer」を選択します。

 

3.

Data Connections」を右クリックして、「Add Connection...」を選択します。

 

4.

Add Connectionダイアログ・ボックスで、適切なデータソース・プロバイダを選択します。

注:Data sourceが、Oracle Database Server(Oracle ODP.NET)にすでに設定されている場合は次の手順に移動するか、「Change」をクリックして、データソース・プロバイダを選択します。

Change Data Sourceダイアログ・ボックスで、Data sourceとして「Oracle Database Server」を選択し、Data providerとして「Oracle Data Provider for .NET」を選択します。 「OK」をクリックします。

 

5.

Data source nameドロップダウンで、使用しているOracleデータベース・インスタンスの<SID>を選択します。 User nameとPasswordにhrと入力し、「Save password」をクリックして「Test connection」をクリックします。

 

6.

テスト接続が成功しました。 「OK」をクリックします。

 

7.

OK」をクリックします。

 

8.

HR接続が作成されました。 同様に、SYSTEM接続も作成する必要があります。 「Data Connections」を右クリックして、「Add Connection...」を選択します。

 

9.

データソース・プロバイダはOracle Database Server(Oracle ODP.NET)に設定されている必要があります。 Data source nameドロップダウンで、使用しているOracleデータベース・インスタンスの<SID>を選択します。

User nameにSYSTEMと入力し、使用しているシステム・パスワードを入力して、「Save password」をクリックし、Roleとして「SYSDBA」を選択して「Test connection」をクリックします。

 

10.

テスト接続が成功しました。 「OK」をクリックします。

 

11.

OK」をクリックします。

 

12.

SYSTEM接続が作成されました。 HR.ORCLとSYSTEM.ORCLの両方を開いて、接続を作成します。

 

デバッガを使用するには、debug connect session権限およびdebug any procedure権限をHRユーザーに付与する必要があります。 以下の手順を実行します。

1.

Server Explorerパネルで、「SYSTEM.ORCL」接続を右クリックして、「Query Window」を選択します。

 

2.

次のコマンドを入力して「Execute」をクリックします。

GRANT debug any procedure, debug connect session TO hr;

注:Oracle Database Release 9.2を使用している場合は、grant debug any procedure to hr;を実行する必要があります。

 

3.

文が正常に実行されました。

 

このトピックでは、PL/SQLパッケージと、PL/SQL配列内の各数値が素数であるかどうかを判定するパッケージ本体を作成し、次にPL/SQLレコードを使用してJOBS表に新しい行を作成します。 以下の手順を実行します。

1.

Server Explorerパネルで、「HR.ORCL」を右クリックして、「Query Window」を選択します。

 

2.

次のコードをコピーしてQueryウィンドウに貼り付けて、「Execute」をクリックします。

CREATE OR REPLACE PACKAGE "HR"."OBE" IS
 -- types for associative arrays that client will pass as arguments
 TYPE "T_IN_VALUES" IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
 TYPE "T_OUT_VALUES" IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
   
   -- procedure that accepts two associative arrays
   -- determines if an element is likely prime and
   -- sets value in output array
   PROCEDURE "DETERMINE_PRIMES" ("P_IN_VALUES" IN T_IN_VALUES,
"P_OUT_VALUES" OUT T_OUT_VALUES); -- function that determines if a number is likely prime FUNCTION "IS_PRIME" ("P_NUMBER" IN NUMBER) RETURN NUMBER; -- constants used to return values from function IS_NOT_A_PRIME CONSTANT NUMBER DEFAULT 0; IS_A_PRIME CONSTANT NUMBER DEFAULT 1; -- pl/sql record type for the jobs table "JOBS_REC" jobs%rowtype; -- pl/sql procedure to add new job to jobs table PROCEDURE "ADD_NEW_JOB" ("P_JOB_ID" IN JOBS.JOB_ID%TYPE, "P_JOB_TITLE" IN JOBS.JOB_TITLE%TYPE, "P_MIN_SALARY" IN JOBS.MIN_SALARY%TYPE, "P_MAX_SALARY" IN JOBS.MAX_SALARY%TYPE); END "OBE";

 

3.

PL/SQLパッケージが正常に実行されました。

 

4.

次のコードをコピーしてQueryウィンドウに貼り付けて、「Execute」をクリックします。

CREATE OR REPLACE PACKAGE BODY "HR"."OBE" IS
-- procedure that processes the incoming associative arrays
-- calls the method IS_PRIME to determine if element is likely prime
PROCEDURE "DETERMINE_PRIMES" ("P_IN_VALUES" IN T_IN_VALUES,
"P_OUT_VALUES" OUT T_OUT_VALUES) IS
BEGIN
-- loop through each element in the incoming array
-- and set the value for the corresponding element
-- in the out array
for i in p_in_values.first..p_in_values.last
loop
p_out_values(i) := is_prime(p_in_values(i));
end loop;
END "DETERMINE_PRIMES";
-- private function to determine if a number is likely prime
FUNCTION "IS_PRIME" ("P_NUMBER" IN NUMBER) RETURN NUMBER IS
l_sqrt number := 0;
l_sqrt_ceil number := 0;
l_divisor number := 0;
l_divisor_squared number := 0;
begin
-- prime numbers must be >= 2
if p_number < 2 then
return IS_NOT_A_PRIME;
end if;
-- only integers can be prime
if p_number != ceil(p_number) then
return IS_NOT_A_PRIME;
end if;
-- 2 is the only even prime, so it is a special case
if p_number = 2 then
return IS_A_PRIME;
end if;
-- eliminate all other even numbers
if mod(p_number,2) = 0 then
return IS_NOT_A_PRIME;
end if;
-- if the sqrt of the number is an integer, the number is not prime
l_sqrt := sqrt(p_number);
l_sqrt_ceil := ceil(l_sqrt);
if l_sqrt = l_sqrt_ceil then
return IS_NOT_A_PRIME;
end if;
-- the number has passed the basic elimination tests and may be prime
-- loop through set of odd divisors to determine if number is prime
l_divisor := 3;
for i in 1..l_sqrt_ceil
loop
l_divisor_squared := l_divisor * l_divisor;
-- if l_divisor is a factor of p_number, then not a prime
if mod(p_number,l_divisor) = 0 and l_divisor_squared < p_number then
return IS_NOT_A_PRIME;
end if;
-- no factor found, therefore number is likely a prime
if l_divisor_squared > p_number then
return IS_A_PRIME;
end if;
l_divisor := l_divisor + 2;
end loop;
END "IS_PRIME";
-- pl/sql procedure to add new job to jobs table
PROCEDURE "ADD_NEW_JOB" ("P_JOB_ID" IN JOBS.JOB_ID%TYPE,
"P_JOB_TITLE" IN JOBS.JOB_TITLE%TYPE,
"P_MIN_SALARY" IN JOBS.MIN_SALARY%TYPE,
"P_MAX_SALARY" IN JOBS.MAX_SALARY%TYPE) IS
BEGIN
-- use the package variable JOBS_REC to create new record
jobs_rec.job_id := p_job_id;
jobs_rec.job_title := p_job_title;
jobs_rec.min_salary := p_min_salary;
jobs_rec.max_salary := p_max_salary;
-- insert the job record into the table
insert into jobs (job_id, job_title, min_salary, max_salary)
values (jobs_rec.job_id, jobs_rec.job_title,
jobs_rec.min_salary, jobs_rec.max_salary);
END "ADD_NEW_JOB";
END "OBE";

 

5.

PL/SQLパッケージ本体が正常に実行されました。

 

6.

Server ExplorerのHR.ORCL接続で、「Packages」→「OBE」を開いて、作成されたオブジェクトの一覧を確認します。

 

7.

OBE」パッケージを右クリックして、「Compile Debug」を選択します。 このアクションで、パッケージのデバッグが有効になります。

 

8.

パッケージが正常にコンパイルされました。 Outputウィンドウを閉じます。 次に、「Start Page」タブをクリックします。

 

これで、新しいプロジェクトを作成できます。 以下の手順を実行します。

1.

Recent Projects領域で、Create:の横にある 「Project...」を選択します。

 

2.

Project TypesでデフォルトのVisual C#を受け入れ、Templatesで「Console Application」を選択して、Nameにplsqldebugobe1と入力し、Locationフィールドにファイルを保存するディレクトリを入力します(注: ディレクトリが存在しない場合は、作成されます)。 「OK」をクリックします。

 

3.

プロジェクトが作成されました。 これで、参照を追加できます。

 

4.

Project...」→「Add Reference...」を選択します。

 

5.

参照のリストを下方向にスクロールし、「Oracle.DataAccess」を選択して「OK」をクリックします。

 

6.

次のコードをコピーして、Visual StudioのProgram.csウィンドウに貼り付けます。 「Program.cs」タブを右クリックして、「Save Program.cs」を選択します。

using System;
using System.Data;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
namespace plsqldebugobe1
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
// constants used to represent values returned
// from the pl/sql procedure call
const int IS_NOT_A_PRIME = 0;
const int IS_A_PRIME = 1;
// display progress message
Console.WriteLine("Testing array for prime numbers...\n");
// connection string: adjust for your environment
string constr = "User Id=hr; Password=hr; Data Source=ORCL; enlist=false; pooling=false";
// create and open connection object
OracleConnection con = new OracleConnection(constr);
con.Open();
// create command object for the function call
OracleCommand cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandText = "OBE.determine_primes";
// set the proper command type
cmd.CommandType = CommandType.StoredProcedure;
// parameter object for the input array
OracleParameter p_in_values = new OracleParameter();
p_in_values.OracleDbType = OracleDbType.Decimal;
p_in_values.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
p_in_values.Value = new decimal[10]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
p_in_values.Size = 10;
p_in_values.Direction = ParameterDirection.Input;
// parameter object for the output array
OracleParameter p_out_values = new OracleParameter();
p_out_values.OracleDbType = OracleDbType.Decimal;
p_out_values.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
p_out_values.Value = null;
p_out_values.Size = 10;
p_out_values.Direction = ParameterDirection.Output;
// add parameters to the collection
// they must be added in the proper
// order when using bind by position (the default)
cmd.Parameters.Add(p_in_values);
cmd.Parameters.Add(p_out_values);
// execute the pl/sql procedure to populate output array
cmd.ExecuteNonQuery();
// display results to console window
for (int i = 0; i < p_in_values.Size; i++)
{
foreach (OracleParameter p in cmd.Parameters)
{
// the input array is treated as System.Decimal[]
// within the .NET code
if (p.Value is System.Decimal[])
{
Console.Write("The Number {0} ", ((p.Value as System.Decimal[])[i]).ToString());
}
// the output array is treated as OracleDecimal[]
// within the .NET code
if (p.Value is OracleDecimal[])
{
if (((p.Value as OracleDecimal[])[i]).ToInt32() == IS_NOT_A_PRIME)
{
Console.WriteLine("is not a prime number!");
}
else if (((p.Value as OracleDecimal[])[i]).ToInt32() == IS_A_PRIME)
{
Console.WriteLine("is a prime number!");
}
}
}
}
// display a separator line
Console.WriteLine();
// display progress message
Console.WriteLine("Using PL/SQL record...\n");
// remove parameters from command collection
// and set new command text
cmd.Parameters.Clear();
cmd.CommandText = "oramag.add_new_job";
// parameter object for the job_id
OracleParameter p_job_id = new OracleParameter();
p_job_id.Value = "IT_DBA";
// parameter object for the job_title
OracleParameter p_job_title = new OracleParameter();
p_job_title.Value = "Database Administrator";
// parameter object for the min_salary
OracleParameter p_min_salary = new OracleParameter();
p_min_salary.OracleDbType = OracleDbType.Decimal;
p_min_salary.Value = 10000;
// parameter object for the max_salary
OracleParameter p_max_salary = new OracleParameter();
p_max_salary.OracleDbType = OracleDbType.Decimal;
p_max_salary.Value = 15000;
// add parameters to collection
cmd.Parameters.Add(p_job_id);
cmd.Parameters.Add(p_job_title);
cmd.Parameters.Add(p_min_salary);
cmd.Parameters.Add(p_max_salary);
// execute the pl/sql procedure to add new job
cmd.ExecuteNonQuery();
// display simple message to indicate procedure completed
Console.WriteLine("New job successfully created!");
// display a separator line
Console.WriteLine();
// Simple prompt to prevent the console from closing
// when running from the IDE
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
// clean up objects
p_max_salary.Dispose();
p_min_salary.Dispose();
p_job_title.Dispose();
p_job_id.Dispose();
p_out_values.Dispose();
p_in_values.Dispose();
cmd.Dispose();
con.Dispose();
}
}
}

 

デバッグ環境を使用するには、事前にいくつかのプロパティとオプションを設定する必要があります。 以下の手順を実行します。

1.

Project」→「plsqldebugobe1 Properties...」を選択します。

 

2.

Debug」を選択します。

 

3.

Enable the Visual Studio hosting process」の選択を解除し、「plsqldebugobe1」タブを右クリックして「Save Selected Items」を選択します。

 

4.

Tools」→「Options...」を選択します。

 

5.

下方向にスクロールして、「Oracle Developer Tools」を開きます。 「PL/SQL Debugging」を選択します。 Available database connectionsで、「HR.ORCL」接続のチェック・ボックスをチェックします。

TCP/IPポートの範囲が表示されるのを確認してください。 PL/SQLのデバッグ中、Oracleデータベースは、この範囲にあるポートをランダムに使用してTCP/IP経由でVisual Studioに接続します。 この範囲が使用しているマシンの開いているポートであること、およびファイアウォールでブロックされていないことを確認してください。

OK」をクリックします。

 

6.

Tools」→「Oracle Application Debugging」を選択します。

もう一度、「Tools」→「Oracle Application Debugging」を選択すると、メニュー項目の前にチェックマークが表示されます。

 

トピック・リストに戻る

このトピックでは、実行中にデバッガを停止するために、C#コードとPL/SQLコードの両方にブレーク・ポイントを設定します。 以下の手順を実行します。

1.

Program.cs」タブをクリックして、cmd.ExecuteNonQuery()文を見つけます。

 

2.

Program.csコードのcmd.Parameters.Add(p_out_values)文にブレーク・ポイントを作成します。 行の任意の場所をクリックし、右クリックして「Breakpoint」を選択します。次に、「Insert Breakpoint」を選択します。 あるいは、ブレーク・ポイントを設定する場所でコード・ウィンドウの一番左端にある灰色部分をクリックすることもできます。

 

3.

ブレーク・ポイント・インジケータが表示されます。

 

4.

パッケージを実行後、別のブレーク・ポイントを作成します。

 

5.

Oracle Explorerで、「DETERMINE_PRIMES」をダブルクリックしてコードをオープンします。

 

6.

DETERMINE_PRIMESプロシージャで、BEGIN文のあとの最初の文にブレーク・ポイントを作成します。

 

7.

プロシージャの一覧から「ADD_NEW_JOB」を選択します。

 

8.

BEGIN文のあとの最初の文にブレーク・ポイントを作成します。

 

9.

Program.cs」タブをクリックします。

 

トピック・リストに戻る

このトピックでは、デバッガを使用してプログラムを実行します。 以下の手順を実行します。

1.

プログラムをデバッグする準備はできています。 「Debug」→「Start Debugging..」を選択します。

 

2.

デバッガが最初のブレーク・ポイントで停止します。 変数とそれぞれの値を確認するには、ウィンドウの下部にある「Local」タブをクリックします。 このブレーク・ポイントまでのコードを確認して、配列バインド・パラメータがどのように設定されているかを理解します。

 

3.

次の行に移動するには、「Step Over」アイコンをクリックします。

 

4.

PL/SQLプロシージャを実行する文に移動しました。 「Step Over」アイコンをクリックします。

 

5.

DETERMINE_PRIMESプロシージャの次のブレーク・ポイントに到達しました。 P_IN_VALUESは、長さが10の配列であるため、ループは10回実行されます。Continue」アイコンを数回クリックして、Localsウィンドウ内の値が変化するのを確認します。

 

6.

LocalsウィンドウのP_IN_VALUES変数名の隣にある+アイコンをクリックして、入力配列の内容を表示します。 これは、C#アプリケーションからこのストアド・プロシージャに渡された値の配列です。 しばらくの間、コードを進めます。 P_OUT_VALUES配列を開いて、最終的にこのストアド・プロシージャによって返される値が入力される様子を確認することもできます。

 

7.

右下にあるウィンドウで「Call Stack」タブをクリックします。 コール・スタックを調べることで、プログラムの現在の実行ポイントまでのコード・パスを特定できます。

 

8.

このブレーク・ポイントを無効にして、プログラムを次のブレーク・ポイントまで進めます。 ブレーク・ポイントを右クリックして、「Disable Breakpoint」を選択します。 赤い円のブレーク・ポイント・アイコンを直接クリックして、ブレーク・ポイントを削除することもできます。

 

9.

Continue」アイコンをクリックして、プログラムを次のブレーク・ポイントまで実行します。

 

10.

コードによってロジックが実行され、ユーザーに表示される内容が生成されます。 「Step Over」をさらに数回クリックします。

 

11.

もう一度、「Continue」アイコンをクリックして、次のブレーク・ポイントに進みます。

 

12.

ADD_NEW_JOBプロシージャのブレーク・ポイントに到達しました。

 

13.

JOBS_REC PL/SQLレコードのグローバル変数を表示する場合は、ウォッチを作成する必要があります。 「JOBS_REC」を選択して右クリックし、「Add Watch」を選択します。 次に、ウィンドウに下部にある「Watch」タブを選択します。

 

14.

Watchウィンドウは、Visual Studioの組込みウィンドウで、特定のプログラム変数を調べることができます。 「JOBS_REC」ウォッチを開きます。

 

15.

Step Over」を4回クリックして、ウォッチが移入されるのを確認します。 次に、「Continue」をクリックします。

 

16.

プログラムの実行が終了すると、結果が表示されます。

 

トピック・リストに戻る

このチュートリアルで学習した内容は、次のとおりです。

データベースへの接続の追加とデバッグ権限の付与
パッケージとパッケージ本体の作成
プロジェクトの作成とデバッグ環境の設定
PL/SQLのデバッグ

トピック・リストに戻る

このアイコンの上にカーソルを置くと、すべてのスクリーンショットが非表示になります。