この例では、Teradata C/C++ UDF Debuggerの並列デバッグ機能を紹介します。SQLリクエストによってUDFが実行されると、UDFの複数のインスタンスが1つ以上のAMP上で実行されることがあります。Teradata C/C++ UDF Debuggerを使用すると、これらのAMP上で実行されているインスタンスを切り替えることができます。この例では、これらのインスタンスをUDFと総称します。
簡単なデバッグの例では、単一のUDFを実行するクエリーを使って、基本的なデバッグ プロセスを示します。この例に従うと、プロセスのステップを正確に再現することができます。この例の詳細は正確に再現することはできません。結果は、使用している特定のデータベース システム構成によって異なります。表示された出力は、ここに示す出力とは異なる場合がありますが、この例では、使用可能なパラレル デバッグ機能の一部を示します。
テーブルの作成
この例に似た結果を出すには、次の値が入力された、"testdata"という名前の2列のテーブルを作成します。
a b --- --- 1 2 2 1 3 4 4 3 5 6 6 5 7 8 8 7 9 10
bteqで次の文を使用してこのテーブルを作成することができます。
create table testdata ( a integer, b integer ) primary index ( a );
このテーブルに、上記の行の値を入力します。それには、これらの値をbteqでINSERT文とともに入力するか、FastLoadを使ってファイルからこれらの値をロードします。
BTEQの使用の詳細については、<Basic Teradata®Queryリファレンス、B035-2414>を参照してください。FastLoadの使用の詳細については、<Teradata® FastLoadリファレンス、B035-2411>を参照してください。
UDFの複数のインスタンスのデバッグ
testdataテーブルの行ごとに、plusudf (簡単なデバッグの例で作成したUDF)を実行するためのリクエストをデバッガで実行します。例えば、次のような文を実行します。
set session debug function plusudf on; select a, b, plusudf(a, b) from testdata;
簡単なデバッグの例で説明されているステップに従います。この問合わせをデバッガに加えると、次のような出力が表示されます。
(gdb) join 1003 Reading symbols for task udfsectsk... (libudf.so, 0x7ffff7bb7000) (libudf1.so, 0x7ffff79b4000) (libstdc++.so.6, 0x7ffff76a9000) (libjil.so, 0x7ffff748b000) (libnetpde.so, 0x7ffff723f000) (libpde.so, 0x7ffff6f80000) (libemf.so, 0x7ffff6d72000) (libpdesym.so, 0x7ffff6b5b000) (libpthread.so.0, 0x7ffff693e000) (libelf.so.1, 0x7ffff672a000) (libnsl.so.1, 0x7ffff6512000) (libm.so.6, 0x7ffff62bc000) (libc.so.6, 0x7ffff5f5a000) (libdl.so.2, 0x7ffff5d56000) (ld-linux-x86-64.so.2, 0x7ffff7dde000) (libgcc_s.so.1, 0x7ffff5b3f000) (libacl.so.1, 0x7ffff5937000) (libcrypto.so.0.9.8, 0x7ffff5598000) (libthread_db.so.1, 0x7ffff5390000) (libattr.so.1, 0x7ffff518b000) (libz.so.1, 0x7ffff4f75000) (libudf_1026_17.so, 0x7ffff355b000) done. Node Pid Tid Type 3 5758 5758 C 2 5748 5748 C 1 5743 5743 C 0 5753 5753 C
この出力では、結合されたUDFを示すテーブル内の行が1つだけ表示されるのではなく、各AMPごと、つまり、Node 3、2、1、0に対して1つの行が表示されています(デバッガはラベル"Node"を使ってvproc番号を示しています。AMPは特定タイプのvprocです)。UDFの12行目にブレークポイントを設定して処理を続行すると、次のような出力が表示されます。
(gdb) b plusudf Breakpoint 1 at 0x7ffff356d12c: file plusudf.c, line 12. (gdb) c Continuing. 0//5753: Secondary breakpoint #1 at plusudf() (plusudf.c line 12) 1//5743: Secondary breakpoint #1 at plusudf() (plusudf.c line 12) 3//5758: Secondary breakpoint #1 at plusudf() (plusudf.c line 12) [Switching to 2//5748] Breakpoint 1, plusudf (a=0x7ffff7fa1940, b=0x7ffff7fa1950, result=0x7ffff7fa1964, sqlstate=0x7ffff7fa196c "00000") at plusudf.c:12 12 *result = *a + *b;
上記の例は、UDFがすべてのAMPにおけるブレークポイントに同時に到達したことを示しています。デバッグはUDF上で順次実行する必要があります。vproc 2のブレークポイントに最初に到達したため、デバッガは現在のコンテキストをそのUDFに切り替えます([Switching to 2//5748]で示されています)。ブレークポイント(vproc 0、1、3)に到達した他のすべてのUDFは、Secondary breakpointとラベル付けされ、ユーザーが現在のコンテキストのスレッドで作業を行なっている間、そのブレークポイントで停止したままになります。
この時点で変数を表示すると、現在のコンテキスト(vproc 2、スレッド57481)のUDFのみが影響を受けます。
(gdb) p *a $1 = 7 (gdb) p *b $2 = 8 (gdb) p *result $3 = 0
ステップ実行すると、関数は停止したローから処理を続行します。
(gdb) n 13 } (gdb) p *result $4 = 15
行が実行され、*resultを出力すると、そのUDFの値が返されることが表示されます。
ブレークポイントで待機中の他のUDFの1つに切り替えることができます。それには、contextコマンド(@記号に省略されています)に続けて、スレッド セレクタを入力します。
(gdb) @ 3//5758 [3//5758] (gdb) p *a $5 = 6
新しいUDFを選択して引数を表示すると、新たに選択されたUDFの値が表示されます。現在停止中のすべてのUDFを処理して、それぞれ個別にステップ実行を行ないます。また、1つのコマンドで、アクティブなすべてのUDFに対してコンテキストを設定し、それらすべてに対しての変数を表示することもできます。
(gdb) @ all [1//5743] (gdb) p *a [1//5743] $6 = 9 [0//5753] $7 = 5 [2//5748] $8 = 7 [3//5758] $9 = 6
1つ以上の特定のスレッド セレクタを指定することで、1つ以上の特定のタスクに対してコンテキストを設定することができます。複数のタスクがコンテキスト内にある場合、各タスクの値の前には、値のスレッド セレクタを示すローがあります。複数のUDFの値を表示することが可能ですが、一度に1つのUDFでのみステップ実行できます。@ allコマンドの後に表示されるスレッド セレクタは、対象となるUDFを示します。
実行を続行すると、現在アクティブなすべてのUDFが再開されます。この例では、最後まで実行されて、次のような結果が出力されます。
(gdb) c Continuing. [Switching to 0//5753] Breakpoint 1, plusudf (a=0x7ffff7fa1940, b=0x7ffff7fa1950, result=0x7ffff7fa1964, sqlstate=0x7ffff7fa196c "00000") at plusudf.c:12 12 *result = *a + *b;
この例の場合、UDFがvproc 0のブレークポイントに到達することに注意してください。これは、UDFが以前完了したvprocと同じですが、今回は別のテーブル行のものです。複数のUDFが同時にブレークポイントに到達すると、セカンダリ ブレークポイントがここで発生する可能性がありますが、この例では、1つのみのUDFがブレークポイントに到達します。
この時点になったら、前述の場合と同様に変数を表示して、新しいUDFのステップスルーを実行できます。
(gdb) p *a $10 = 3 (gdb) p *b $11 = 4 (gdb) n 13 } (gdb) p *result $12 = 7
デバッガが停止するといつでも、ブレークポイントに到達したUDFを報告するだけで、デバッガが結合したすべてのUDFの実行を一時停止します。他のUDFを表示する場合は、すべてのスレッドをコンテキスト(@ all)に入れ、info context longコマンドを実行してコンテキスト内の全スレッドを表示します。この時点のデバッグ セッションの出力は次のようになります。
(gdb) @ all [2//5748] (gdb) i context long all -> 2//5748 0//5753
UDF 2//5748は、デバッガがブレークポイントに到達したときには報告されませんでした。このUDFはデバッガに加わりましたが、すべてのUDFが停止したときに、まだブレークポイントに到達していませんでした。2//5748のUDF変数を出力しようとしても、変数を定義する行内で実行が停止したため、変数は出力されません。
(gdb) p *a [2//5748] No symbol "a" in current context. [0//5753] $15 = 3
この時点で処理を再び続行すると、2//5748をブレークポイントに到達するまで実行できます。
(gdb) c Continuing. Breakpoint 1, plusudf (a=0x7ffff7fa1940, b=0x7ffff7fa1950, result=0x7ffff7fa1964, sqlstate=0x7ffff7fa196c "00000") at plusudf.c:12 12 *result = *a + *b; (gdb) info context 2//5748
以前の@コマンドで設定された現在のコンテキストには、停止したスレッドがすでに含まれているため、コンテキストの切り替えに関するメッセージはここでは表示されません。停止後のコンテキストを表示すると、どのスレッドが停止したかを確認できます。この場合は、2//5748です。
再び処理を続行すると、このスレッドを実行することができ、1つ以上のUDFがブレークポイントに到達するとデバッガが停止します。UDFがテーブルのすべての行に対して実行されるまで、処理を続行できます。すべてのUDFを順次処理する必要がない場合は、デバッガを終了できます。デバッガを終了すると、問合わせは停止せずに最後まで実行されます。あるいは、ブレークポイントを削除または無効にして、デバッグを終了せずに処理を続行して、問合わせを終了させることができます。その時点で問合わせを再実行すると、最初のUDFが実行されたときに、問合わせは再び停止します。
並列デバッグは、この単純な例に示すよりも多くの機能を提供します。ごく少数のUDFによって実行される問題コードを順次処理するだけの場合は、その時点でブレークポイントを設定すると、ブレークポイントに到達したUDFのみが停止します。他のすべてのUDFは停止することなくサイレント実行されます。また、対象のデータ値がUDFに渡されたときにだけ停止するように、ブレークポイントに条件を設定することもできます。ブレークポイントに到達する度に変数を自動的に表示するブレークポイントにコマンドを接続することができます。最後のコマンドで実行を続けることで、問合わせによってまったく停止せずに実行されるUDFのトレースを生成できます。