メタデータの取得と記述子領域
動的SQLだと,スキーマを事前に予測できない場合がある.記述子領域は,メタデータとデータのデータセットで,これを使用すると,埋め込みSQLでもメタデータを扱えるようになる.
以下を使用すればプログラム実行時にいかなるスキーマのテーブルをも作成することができる.
EXEC SQL EXECUTE IMMEDIATE 文字列;問題はこのプログラム実行時にスキーマが決定されるテーブルから,どうやってデータを取り出すかである.静的な埋め込みSQLではスキーマがあらかじめ分かっている状況を扱うので,取り出したデータを格納する変数の型と数をコードにあらかじめ記述できた.こうした問題を解決するために,記述子領域というものを使用する.記述子領域には以下が含まれている.
- ヘッダ
- メタデータ
- データ(検索結果1行分)
記述子領域を使用するサンプルを以下にしめす.
上のサンプルではinit.pcgとfin.pcgをEXEC SQL INCLUDEしている.init.pcgでテーブルhogeを作成しデータを投入する.上のサンプル本体はテーブルhogeのスキーマがどうなっているを調べるので,init.pcgでテーブルhogeのスキーマは好きなようにできる.今回はinit.pcgを以下のようにした.
fin.pcgは,サンプルを繰り返し実行できるよう,init.pcgで作成したテーブルをドロップするようにした.
実行結果を以下に示す(今回はecpgのデバッグ文は抑止した).
$> ./descriptor -d tcp:postgresql://dbserver/firstdb -u matsu -p hogefuga
record 01
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="1"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data="foovar01"
indicator = 0 / datalength = 8
record 02
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="3"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data="foovar03"
indicator = 0 / datalength = 8
record 03
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="5"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data="foovar05"
indicator = 0 / datalength = 8
record 04
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="7"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data="foovar07"
indicator = 0 / datalength = 8
record 05
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="9"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data="foovar09"
indicator = 0 / datalength = 8
record 06
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="0"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data=""
indicator = -1 / datalength = 8
record 07
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="2"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data=""
indicator = -1 / datalength = 8
record 08
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="4"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data=""
indicator = -1 / datalength = 8
record 09
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="6"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data=""
indicator = -1 / datalength = 8
record 10
fieldno = 1 / fieldname = "id" / fieldtype = 4 data="8"
indicator = 0 / datalength = -5
fieldno = 2 / fieldname = "name" / fieldtype = 1 data=""
indicator = -1 / datalength = 8
各レコードについて全フィールド(といっても二つだけど)の名前や型などを取り出している.
記述子領域の使用の流れは大体以下のようになるだろう.
- 記述子領域の確保とカーソル定義/オープン
- フェッチ
- 記述子領域からメタデータを取り出す
- 記述子領域からデータを取り出す
- 記述子領域の開放とカーソルクローズ
EXEC SQL ALLOCATE DESCRIPTOR 記述子名;そして領域確保した記述子をフェッチのINTO句に使用する.
EXEC SQL FETCH NEXT FROM カーソル名 INTO DESCRIPTOR 記述子名;これで記述子領域にメタデータとともにフェッチ結果が格納される.記述子領域の使用が終ったら開放する.
EXEC SQL DEALLOCATE DESCRIPTOR 記述子名;
INTO句に記述子領域を指定してフェッチしたら,記述子領域からデータを取り出せる.まず以下で記述子領域のヘッダデータを取り出す.
EXEC SQL GET DESCRIPTOR 記述子領域名 格納変数 = フィールド名;フィールドはCOUNT(列数)だけらしい.以下はサンプルでの記述.
/* 列数の取得 */ EXEC SQL GET DESCRIPTOR descriptor1 :fieldcount = COUNT;上で列数が分かったので,サンプルではその列数分メタデータとデータの取り出しを行っている.
for (fieldno = 1; fieldno <= fieldcount; fieldno++)
{
EXEC SQL GET DESCRIPTOR descriptor1 VALUE :fieldno :fieldname = NAME;
EXEC SQL GET DESCRIPTOR descriptor1 VALUE :fieldno :fieldtype = TYPE;
EXEC SQL GET DESCRIPTOR descriptor1 VALUE :fieldno :fielddata = DATA;
EXEC SQL GET DESCRIPTOR descriptor1 VALUE :fieldno :fieldindicator = INDICATOR;
EXEC SQL GET DESCRIPTOR descriptor1 VALUE :fieldno :fielddatalength = LENGTH;
fprintf (stderr,
"\tfieldno = %d / fieldname = \"%s\" / fieldtype = %d data=\"%s\"\n",
fieldno, fieldname, fieldtype, fielddata);
fprintf (stderr, "\t\tindicator = %d / datalength = %d \n",
fieldindicator, fielddatalength);
}
記述子領域本体のデータを取り出す構文は以下である(※).
EXEC SQL GET DESCRIPTOR 記述子領域名 VALUE 列番号 変数 = メタデータのフィールド名;サンプルで取得しているメタデータのフィールドを以下に示す.
- NAME
- フィールド名(列名)
- TYPE
- フィールドの型
- DATA
- フィールドの値
- INDICATOR
- NULLなら負,正なら切り詰められた,0なら正常.
- LENGTH
- DATAの文字列としての長さ.サンプルの実行結果からすると,TYPEが文字列でなければ負になるようだ.
※ 「フィールド」というのがメタデータの項目のことなのか,テーブルの列,属性なのかに注意しないと混乱する.前者の場合は「メタデータの」とつけるようにした.

