バージョンごとのドキュメント一覧

36.7. 記述子領域の使用 #

<title>Using Descriptor Areas</title>

An SQL descriptor area is a more sophisticated method for processing the result of a <command>SELECT</command>, <command>FETCH</command> or a <command>DESCRIBE</command> statement. An SQL descriptor area groups the data of one row of data together with metadata items into one data structure. The metadata is particularly useful when executing dynamic SQL statements, where the nature of the result columns might not be known ahead of time. PostgreSQL provides two ways to use Descriptor Areas: the named SQL Descriptor Areas and the C-structure SQLDAs. SQL記述子領域はSELECTFETCHDESCRIBE文の結果を処理する、より洗練された手法です。 SQL記述子領域は1行のデータをメタデータ項目と一緒に1つのデータ構造体としてグループ化します。 特に動的SQL文を実行する場合は結果列の性質が前もってわかりませんので、メタデータが有用です。 PostgreSQLは記述子領域を使用するための2つの方法、名前付きSQL記述子領域とC構造化SQLDA、を提供します。

36.7.1. 名前付きSQL記述子領域 #

<title>Named SQL Descriptor Areas</title>

A named SQL descriptor area consists of a header, which contains information concerning the entire descriptor, and one or more item descriptor areas, which basically each describe one column in the result row. 名前付きSQL記述子領域は、記述子全体に関する情報を持つヘッダと、基本的に結果行内の1つの列を記述する、1つ以上の項目記述子領域から構成されます。

Before you can use an SQL descriptor area, you need to allocate one: SQL記述子領域を使用可能にするためには、それを以下のように割り当てなければなりません。

EXEC SQL ALLOCATE DESCRIPTOR identifier;

The identifier serves as the <quote>variable name</quote> of the descriptor area. <!&#45;- The scope of the allocated descriptor is WHAT?. &#45;-> When you don't need the descriptor anymore, you should deallocate it: この識別子は記述子領域の変数名として使用されます。 割り当てられた記述子のスコープは何でしょう? 記述子が不要になったら、以下のように解放してください。

EXEC SQL DEALLOCATE DESCRIPTOR identifier;

To use a descriptor area, specify it as the storage target in an <literal>INTO</literal> clause, instead of listing host variables: 記述子領域を使用するには、INTO句内の格納対象として、ホスト変数を列挙するのではなく、記述子領域を指定してください。

EXEC SQL FETCH NEXT FROM mycursor INTO SQL DESCRIPTOR mydesc;

If the result set is empty, the Descriptor Area will still contain the metadata from the query, i.e., the field names. 結果セットが空の場合であっても、記述子領域には問い合わせのメタデータ、つまりフィールド名、が含まれます。

For not yet executed prepared queries, the <command>DESCRIBE</command> statement can be used to get the metadata of the result set: まだ実行されていないプリペアド問い合わせでは、結果セットのメタデータを入手するためにDESCRIBEを使用することができます。

EXEC SQL BEGIN DECLARE SECTION;
char *sql_stmt = "SELECT * FROM table1";
EXEC SQL END DECLARE SECTION;

EXEC SQL PREPARE stmt1 FROM :sql_stmt;
EXEC SQL DESCRIBE stmt1 INTO SQL DESCRIPTOR mydesc;

Before PostgreSQL 9.0, the <literal>SQL</literal> keyword was optional, so using <literal>DESCRIPTOR</literal> and <literal>SQL DESCRIPTOR</literal> produced named SQL Descriptor Areas. Now it is mandatory, omitting the <literal>SQL</literal> keyword produces SQLDA Descriptor Areas, see <xref linkend="ecpg-sqlda-descriptors"/>. PostgreSQL 9.0より前では、SQLキーワードは省略可能でした。 このためDESCRIPTORおよびSQL DESCRIPTORは名前付きSQL記述子領域を生成しました。 これは強制事項になり、SQLキーワードを省略すると、SQLDA記述子領域を生成します。 36.7.2を参照してください。

In <command>DESCRIBE</command> and <command>FETCH</command> statements, the <literal>INTO</literal> and <literal>USING</literal> keywords can be used to similarly: they produce the result set and the metadata in a Descriptor Area. DESCRIBEおよびFETCH文では、INTOおよびUSINGキーワードを同じように使用することができます。 これらは結果セットと記述子領域内のメタデータを生成します。

Now how do you get the data out of the descriptor area? You can think of the descriptor area as a structure with named fields. To retrieve the value of a field from the header and store it into a host variable, use the following command: さて、どうやって記述子領域からデータを取り出すのでしょうか。 この記述子領域を名前付きフィールドを持つ構造体とみなすことができます。 ヘッダからフィールド値を取り出し、それをホスト変数に格納するには、以下のコマンドを使用します。

EXEC SQL GET DESCRIPTOR name :hostvar = field;

Currently, there is only one header field defined: <replaceable>COUNT</replaceable>, which tells how many item descriptor areas exist (that is, how many columns are contained in the result). The host variable needs to be of an integer type. To get a field from the item descriptor area, use the following command: 今のところ、COUNTというヘッダフィールドが1つだけ定義されています。 これは、記述子領域に存在する項目数を表すものです (つまり、結果内に含まれる列数です)。 このホスト変数は整数型でなければなりません。 項目記述子領域からフィールドを取り出すには、以下のコマンドを使用します。

EXEC SQL GET DESCRIPTOR name VALUE num :hostvar = field;

<replaceable>num</replaceable> can be a literal integer or a host variable containing an integer. Possible fields are: numはリテラル整数、もしくは整数を持つホスト変数を取ることができます。 取り得るフィールドは以下の通りです。

CARDINALITY (整数) #

number of rows in the result set 結果セット内の行数です。

DATA #

actual data item (therefore, the data type of this field depends on the query) 実際のデータ項目です (したがってこのフィールドのデータ型は問い合わせに依存します)。

DATETIME_INTERVAL_CODE (整数) #

When <literal>TYPE</literal> is <literal>9</literal>, <literal>DATETIME_INTERVAL_CODE</literal> will have a value of <literal>1</literal> for <literal>DATE</literal>, <literal>2</literal> for <literal>TIME</literal>, <literal>3</literal> for <literal>TIMESTAMP</literal>, <literal>4</literal> for <literal>TIME WITH TIME ZONE</literal>, or <literal>5</literal> for <literal>TIMESTAMP WITH TIME ZONE</literal>. TYPE9の場合、DATETIME_INTERVAL_CODEは、DATEでは1TIMEでは2TIMESTAMPでは3TIME WITH TIME ZONEでは4TIMESTAMP WITH TIME ZONEでは5という値を取ります。

DATETIME_INTERVAL_PRECISION (整数) #

not implemented 未実装です。

INDICATOR (整数) #

the indicator (indicating a null value or a value truncation) (NULL値や値の切り詰めを示す)指示子です。

KEY_MEMBER (整数) #

not implemented 実装されていません。

LENGTH (整数) #

length of the datum in characters データの文字列の長さです。

NAME (文字列) #

name of the column 列名です。

NULLABLE (整数) #

not implemented 実装されていません。

OCTET_LENGTH (整数) #

length of the character representation of the datum in bytes データの文字表現のバイト長です。

PRECISION (整数) #

precision (for type <type>numeric</type>) numeric型用の)精度です。

RETURNED_LENGTH (整数) #

length of the datum in characters データの文字数です。

RETURNED_OCTET_LENGTH (整数) #

length of the character representation of the datum in bytes データの文字表現のバイト長です。

SCALE (整数) #

scale (for type <type>numeric</type>) numeric型用の)桁です。

TYPE (整数) #

numeric code of the data type of the column 列のデータ型の数値コードです。

In <command>EXECUTE</command>, <command>DECLARE</command> and <command>OPEN</command> statements, the effect of the <literal>INTO</literal> and <literal>USING</literal> keywords are different. A Descriptor Area can also be manually built to provide the input parameters for a query or a cursor and <literal>USING SQL DESCRIPTOR <replaceable>name</replaceable></literal> is the way to pass the input parameters into a parameterized query. The statement to build a named SQL Descriptor Area is below: EXECUTEDECLAREおよびOPEN文では、INTOおよびUSINGの効果は異なります。 また、問い合わせやカーソル用の入力パラメータを提供するために記述子領域は手作業で構築することができます。 USING SQL DESCRIPTOR nameは入力パラメータとパラメータ付きの問い合わせに渡す方法です。 名前付きSQL記述子領域を構築するSQL文は以下の通りです。

EXEC SQL SET DESCRIPTOR name VALUE num field = :hostvar;

PostgreSQL supports retrieving more that one record in one <command>FETCH</command> statement and storing the data in host variables in this case assumes that the variable is an array. E.g.: PostgreSQLは、1つのFETCH文内の1レコードを複数取り出し、ホスト変数に格納することをサポートします。 この場合ホスト変数は配列であると仮定されます。

EXEC SQL BEGIN DECLARE SECTION;
int id[5];
EXEC SQL END DECLARE SECTION;

EXEC SQL FETCH 5 FROM mycursor INTO SQL DESCRIPTOR mydesc;

EXEC SQL GET DESCRIPTOR mydesc VALUE 1 :id = DATA;

36.7.2. SQLDA記述子領域 #

<title>SQLDA Descriptor Areas</title>

An SQLDA Descriptor Area is a C language structure which can be also used to get the result set and the metadata of a query. One structure stores one record from the result set. SQLDA記述子領域は、問い合わせの結果セットとメタデータを取り出すために使用可能なC言語の構造体です。 1つの構造体には結果セットの1レコードが格納されます。

EXEC SQL include sqlda.h;
sqlda_t         *mysqlda;

EXEC SQL FETCH 3 FROM mycursor INTO DESCRIPTOR mysqlda;

Note that the <literal>SQL</literal> keyword is omitted. The paragraphs about the use cases of the <literal>INTO</literal> and <literal>USING</literal> keywords in <xref linkend="ecpg-named-descriptors"/> also apply here with an addition. In a <command>DESCRIBE</command> statement the <literal>DESCRIPTOR</literal> keyword can be completely omitted if the <literal>INTO</literal> keyword is used: SQLキーワードが省略されていることに注意してください。 36.7.1INTOおよびUSINGの使用状況に関する段落はここで多少追加して適用します。 DESCRIBE文では、INTOが使用されている場合DESCRIPTORキーワードは完全に省略可能です。

EXEC SQL DESCRIBE prepared_statement INTO mysqlda;

The general flow of a program that uses SQLDA is: SQLDAを使用するプログラムの一般的な流れは以下の通りです。

<step><simpara>Prepare a query, and declare a cursor for it.</simpara></step> <step><simpara>Declare an SQLDA for the result rows.</simpara></step> <step><simpara>Declare an SQLDA for the input parameters, and initialize them (memory allocation, parameter settings).</simpara></step> <step><simpara>Open a cursor with the input SQLDA.</simpara></step> <step><simpara>Fetch rows from the cursor, and store them into an output SQLDA.</simpara></step> <step><simpara>Read values from the output SQLDA into the host variables (with conversion if necessary).</simpara></step> <step><simpara>Close the cursor.</simpara></step> <step><simpara>Free the memory area allocated for the input SQLDA.</simpara></step>
  1. 問い合わせをプリペアし、そのカーソルを宣言します。

  2. 結果セット用のSQLDAを宣言します。

  3. 入力パラメータ用のSQLDAを宣言し、初期化(メモリ割り当て、パラメータの設定)します。

  4. 入力用SQLDAでカーソルを開きます。

  5. カーソルから行を取り出し、出力用SQLDAに格納します。

  6. 出力用SQLDAから値をホスト変数に(必要に応じて変換を行い)読み取ります。

  7. カーソルを閉じます。

  8. 入力用SQLDAに割り当てられたメモリ領域を解放します。

36.7.2.1. SQLDAのデータ構造 #

<title>SQLDA Data Structure</title>

SQLDA uses three data structure types: <type>sqlda_t</type>, <type>sqlvar_t</type>, and <type>struct sqlname</type>. SQLDAはsqlda_tsqlvar_tstruct sqlnameという3つの種類のデータ構造を使用します。

ヒント

PostgreSQL's SQLDA has a similar data structure to the one in IBM DB2 Universal Database, so some technical information on DB2's SQLDA could help understanding PostgreSQL's one better. PostgreSQLのSQLDAはIBM DB2ユニバーサルデータベースのものと似たデータ構造を持ちます。 このため、DB2のSQLDAに関する技術情報の一部はPostgreSQLのSQLDAの理解のより良い助けになるでしょう。

36.7.2.1.1. sqlda_t構造体 #
<title>sqlda_t Structure</title>

The structure type <type>sqlda_t</type> is the type of the actual SQLDA. It holds one record. And two or more <type>sqlda_t</type> structures can be connected in a linked list with the pointer in the <structfield>desc_next</structfield> field, thus representing an ordered collection of rows. So, when two or more rows are fetched, the application can read them by following the <structfield>desc_next</structfield> pointer in each <type>sqlda_t</type> node. sqlda_t構造体は実際のSQLDAの型です。 これは1つのレコードを保持します。 そして2つ以上のsqlda_t構造体をdesc_nextフィールド内においてポインタを使ってリンクリスト内でつなげることができます。 こうして行の順序付き集合を表現します。 このため、2つ以上の行を取り出す時、アプリケーションは各sqlda_tノードのdesc_nextポインタを追うことでそれらを読み取ることができます。

The definition of <type>sqlda_t</type> is: sqlda_tの定義は以下の通りです。

struct sqlda_struct
{
    char            sqldaid[8];
    long            sqldabc;
    short           sqln;
    short           sqld;
    struct sqlda_struct *desc_next;
    struct sqlvar_struct sqlvar[1];
};

typedef struct sqlda_struct sqlda_t;

The meaning of the fields is: フィールドの意味は以下の通りです。

sqldaid #

It contains the literal string <literal>"SQLDA "</literal>. ここには"SQLDA "文字列リテラルが含まれます。

sqldabc #

It contains the size of the allocated space in bytes. ここにはバイト単位の割り当てられた領域のサイズが含まれます。

sqln #

It contains the number of input parameters for a parameterized query in case it's passed into <command>OPEN</command>, <command>DECLARE</command> or <command>EXECUTE</command> statements using the <literal>USING</literal> keyword. In case it's used as output of <command>SELECT</command>, <command>EXECUTE</command> or <command>FETCH</command> statements, its value is the same as <literal>sqld</literal> statement USINGキーワードを使用してOPENDECLAREEXECUTE文に渡される場合、ここにはパラメータ付き問い合わせの入力パラメータ数が含まれます。 SELECTEXECUTEFETCH文の出力として使用される場合、この値はsqld文と同じです。

sqld #

It contains the number of fields in a result set. ここには結果セットのフィールド数が含まれます。

desc_next #

If the query returns more than one record, multiple linked SQLDA structures are returned, and <literal>desc_next</literal> holds a pointer to the next entry in the list. 問い合わせが複数のレコードを返す場合、複数結び付いたSQLDA構造体が返されます。 desc_nextにリスト内の次の項目を指し示すポインタが保持されます。

sqlvar #

This is the array of the columns in the result set. これは結果セット内の列の配列です。

36.7.2.1.2. sqlvar_t構造体 #
<title>sqlvar_t Structure</title>

The structure type <type>sqlvar_t</type> holds a column value and metadata such as type and length. The definition of the type is: sqlvar_t構造体は列の値と型や長さなどのメタデータを保持します。 この型の定義は以下の通りです。

struct sqlvar_struct
{
    short          sqltype;
    short          sqllen;
    char          *sqldata;
    short         *sqlind;
    struct sqlname sqlname;
};

typedef struct sqlvar_struct sqlvar_t;

The meaning of the fields is: フィールドの意味は以下の通りです。

sqltype #

Contains the type identifier of the field. For values, see <literal>enum ECPGttype</literal> in <literal>ecpgtype.h</literal>. ここにはフィールドの型識別子が含まれます。 値についてはecpgtype.henum ECPGttypeを参照してください。

sqllen #

Contains the binary length of the field. e.g., 4 bytes for <type>ECPGt_int</type>. フィールドのバイナリ長が含まれます。 例えばECPGt_intでは4バイトです。

sqldata #

Points to the data. The format of the data is described in <xref linkend="ecpg-variables-type-mapping"/>. データそのものを指し示します。 データ書式は36.4.4で説明します。

sqlind #

Points to the null indicator. 0 means not null, -1 means null. データのNULL指示子を指し示します。 0は非NULLを、-1はNULLを意味します。

sqlname #

The name of the field. フィールドの名前です。

36.7.2.1.3. struct sqlname構造体 #
<title>struct sqlname Structure</title>

A <type>struct sqlname</type> structure holds a column name. It is used as a member of the <type>sqlvar_t</type> structure. The definition of the structure is: struct sqlname構造体は列名を保持します。 sqlvar_t構造体のメンバとして使用されます。 構造体の定義は以下の通りです。

#define NAMEDATALEN 64

struct sqlname
{
        short           length;
        char            data[NAMEDATALEN];
};

The meaning of the fields is: フィールドの意味は以下の通りです。

length #

Contains the length of the field name. フィールド名の長さが含まれます。

data #

Contains the actual field name. 実際のフィールド名が含まれます。

36.7.2.2. SQLDAを使用した結果セットの取り出し #

<title>Retrieving a Result Set Using an SQLDA</title>

The general steps to retrieve a query result set through an SQLDA are: SQLDAを通して問い合わせの結果を取り出す一般的な手順は以下に示します。

<step><simpara>Declare an <type>sqlda_t</type> structure to receive the result set.</simpara></step> <step><simpara>Execute <command>FETCH</command>/<command>EXECUTE</command>/<command>DESCRIBE</command> commands to process a query specifying the declared SQLDA.</simpara></step> <step><simpara>Check the number of records in the result set by looking at <structfield>sqln</structfield>, a member of the <type>sqlda_t</type> structure.</simpara></step> <step><simpara>Get the values of each column from <literal>sqlvar[0]</literal>, <literal>sqlvar[1]</literal>, etc., members of the <type>sqlda_t</type> structure.</simpara></step> <step><simpara>Go to next row (<type>sqlda_t</type> structure) by following the <structfield>desc_next</structfield> pointer, a member of the <type>sqlda_t</type> structure.</simpara></step> <step><simpara>Repeat above as you need.</simpara></step>
  1. 結果セットを受けとるためのsqlda_t構造体を宣言します。

  2. 宣言したSQLDAを指定した問い合わせを処理するためにFETCH/EXECUTE/DESCRIBEを実行します。

  3. sqlda_t構造体のメンバsqlnを検索することにより結果セット内のレコード数を検査します。

  4. sqlda_t構造体のメンバsqlvar[0]sqlvar[1]などから各列の値を入手します。

  5. sqlda_t構造体のメンバdesc_nextポインタを追い、次の行(sqlda_t構造体)に進みます。

  6. 必要なだけ上を繰り返します。

Here is an example retrieving a result set through an SQLDA. 以下にSQLDAを通して結果セットを取り出す例を示します。

First, declare a <type>sqlda_t</type> structure to receive the result set. まず、結果セットを受け取るsqlda_t構造体を宣言します。

sqlda_t *sqlda1;

Next, specify the SQLDA in a command. This is a <command>FETCH</command> command example. 次にコマンド内にSQLDAを指定します。 以下はFETCHコマンドの例です。

EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

Run a loop following the linked list to retrieve the rows. 行を取り出すためにリンクリストを追うループを実行します。

sqlda_t *cur_sqlda;

for (cur_sqlda = sqlda1;
     cur_sqlda != NULL;
     cur_sqlda = cur_sqlda->desc_next)
{
    ...
}

Inside the loop, run another loop to retrieve each column data (<type>sqlvar_t</type> structure) of the row. ループの内側では、行の列データ(sqlvar_t構造体)それぞれを取り出す別のループを実行します。

for (i = 0; i < cur_sqlda->sqld; i++)
{
    sqlvar_t v = cur_sqlda->sqlvar[i];
    char *sqldata = v.sqldata;
    short sqllen  = v.sqllen;
    ...
}

To get a column value, check the <structfield>sqltype</structfield> value, a member of the <type>sqlvar_t</type> structure. Then, switch to an appropriate way, depending on the column type, to copy data from the <structfield>sqlvar</structfield> field to a host variable. 列の値を入手するために、sqlvar_t構造体のメンバsqltypeの値を検査します。 そして、列の型に応じて、sqlvarフィールドからホスト変数にデータをコピーするための適切な方法に切り替えます。

char var_buf[1024];

switch (v.sqltype)
{
    case ECPGt_char:
        memset(&var_buf, 0, sizeof(var_buf));
        memcpy(&var_buf, sqldata, (sizeof(var_buf) <= sqllen ? sizeof(var_buf) - 1 : sqllen));
        break;


    case ECPGt_int: /* integer */

    case ECPGt_int: /* 整数 */
        memcpy(&intval, sqldata, sqllen);
        snprintf(var_buf, sizeof(var_buf), "%d", intval);
        break;

    ...
}

36.7.2.3. SQLDAを使用した問い合わせパラメータ渡し #

<title>Passing Query Parameters Using an SQLDA</title>

The general steps to use an SQLDA to pass input parameters to a prepared query are: プリペアド問い合わせに入力パラメータを渡すためにSQLDAを使用する、一般的な手順は以下の通りです。

<step><simpara>Create a prepared query (prepared statement)</simpara></step> <step><simpara>Declare an sqlda_t structure as an input SQLDA.</simpara></step> <step><simpara>Allocate memory area (as sqlda_t structure) for the input SQLDA.</simpara></step> <step><simpara>Set (copy) input values in the allocated memory.</simpara></step> <step><simpara>Open a cursor with specifying the input SQLDA.</simpara></step>
  1. プリペアド問い合わせ(プリペアド文)を作成します。

  2. 入力用SQLDAとしてsqlda_t構造体を宣言します。

  3. 入力用SQLDA用にメモリ領域を(sqlda_t構造体として)割り当てます。

  4. 割り当てたメモリに入力値を設定(コピー)します。

  5. 入力用SQLDAを指定してカーソルを開きます。

Here is an example. 以下に例を示します。

First, create a prepared statement. まずプリペアド文を作成します。

EXEC SQL BEGIN DECLARE SECTION;
char query[1024] = "SELECT d.oid, * FROM pg_database d, pg_stat_database s WHERE d.oid = s.datid AND (d.datname = ? OR d.oid = ?)";
EXEC SQL END DECLARE SECTION;

EXEC SQL PREPARE stmt1 FROM :query;

Next, allocate memory for an SQLDA, and set the number of input parameters in <structfield>sqln</structfield>, a member variable of the <type>sqlda_t</type> structure. When two or more input parameters are required for the prepared query, the application has to allocate additional memory space which is calculated by (nr. of params - 1) * sizeof(sqlvar_t). The example shown here allocates memory space for two input parameters. 次にSQLDA用にメモリを割り当て、sqlda_t構造体のメンバ変数sqlnに入力パラメータ数を設定します。 プリペアド問い合わせで2つ以上の入力パラメータが必要な場合、アプリケーションは(パラメータ数 - 1) * sizeof(sqlvar_t)で計算される追加のメモリ空間を割り当てなければなりません。 ここで示す例では2つの入力パラメータ用にメモリ空間を割り当てます。

sqlda_t *sqlda2;

sqlda2 = (sqlda_t *) malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));


sqlda2->sqln = 2; /* number of input variables */

sqlda2->sqln = 2; /* 入力変数の個数 */

After memory allocation, store the parameter values into the <literal>sqlvar[]</literal> array. (This is same array used for retrieving column values when the SQLDA is receiving a result set.) In this example, the input parameters are <literal>"postgres"</literal>, having a string type, and <literal>1</literal>, having an integer type. メモリを割り当てた後、sqlvar[]配列にパラメータ値を格納します。 (これは、SQLDAが結果セットを受け取る時に列値を取り出すために使用した配列と同じです。) この例では、入力パラメータは文字列型を持つ"postgres"と整数型を持つ1です。

sqlda2->sqlvar[0].sqltype = ECPGt_char;
sqlda2->sqlvar[0].sqldata = "postgres";
sqlda2->sqlvar[0].sqllen  = 8;

int intval = 1;
sqlda2->sqlvar[1].sqltype = ECPGt_int;
sqlda2->sqlvar[1].sqldata = (char *) &intval;
sqlda2->sqlvar[1].sqllen  = sizeof(intval);

By opening a cursor and specifying the SQLDA that was set up beforehand, the input parameters are passed to the prepared statement. ここまでで設定したSQLDAを指定するカーソルを開くことで、入力パラメータはプリペアド文に渡されます。

EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

Finally, after using input SQLDAs, the allocated memory space must be freed explicitly, unlike SQLDAs used for receiving query results. 最後に、問い合わせ結果を受け取るために使用するSQLDAとは異なり、入力用SQLDAの使用後、割り当てたメモリ空間を明示的に解放しなければなりません。

free(sqlda2);

36.7.2.4. SQLDAを使用するサンプルアプリケーション #

<title>A Sample Application Using SQLDA</title>

Here is an example program, which describes how to fetch access statistics of the databases, specified by the input parameters, from the system catalogs. 以下に、システムカタログから入力パラメータにより指定されたデータベースの統計情報にアクセスし取り出す方法を示す、プログラム例を示します。

This application joins two system tables, pg_database and pg_stat_database on the database OID, and also fetches and shows the database statistics which are retrieved by two input parameters (a database <literal>postgres</literal>, and OID <literal>1</literal>). このアプリケーションは、pg_databaseとpg_stat_databaseシステムテーブルをデータベースOIDで結合し、2つの入力パラメータ(データベースpostgresとOID1)により取り出されるデータベース統計情報を読み取り、表示します。

First, declare an SQLDA for input and an SQLDA for output. まず、入力用のSQLDAと出力用のSQLDAを宣言します。

EXEC SQL include sqlda.h;


sqlda_t *sqlda1; /* an output descriptor */
sqlda_t *sqlda2; /* an input descriptor  */

sqlda_t *sqlda1; /* 出力記述子 */
sqlda_t *sqlda2; /* 入力記述子 */

Next, connect to the database, prepare a statement, and declare a cursor for the prepared statement. 次に、データベースに接続し、プリペアド文を作成し、プリペアド文用のカーソルを宣言します。

int
main(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char query[1024] = "SELECT d.oid,* FROM pg_database d, pg_stat_database s WHERE d.oid=s.datid AND ( d.datname=? OR d.oid=? )";
    EXEC SQL END DECLARE SECTION;

    EXEC SQL CONNECT TO testdb AS con1 USER testuser;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;

    EXEC SQL PREPARE stmt1 FROM :query;
    EXEC SQL DECLARE cur1 CURSOR FOR stmt1;

Next, put some values in the input SQLDA for the input parameters. Allocate memory for the input SQLDA, and set the number of input parameters to <literal>sqln</literal>. Store type, value, and value length into <literal>sqltype</literal>, <literal>sqldata</literal>, and <literal>sqllen</literal> in the <literal>sqlvar</literal> structure. 次に、入力パラメータのために入力用SQLDA内にいくつかの値を格納します。 入力用SQLDAのためのメモリを割り当て、入力パラメータの個数をsqlnに設定します。 型、値、値の長さをsqlvar構造体内のsqltypesqldatasqllenに格納します。


    /* Create SQLDA structure for input parameters. */

    /* 入力パラメータ用のSQLDA構造体を作成する。 */
    sqlda2 = (sqlda_t *) malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
    memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));

    sqlda2->sqln = 2; /* number of input variables */

    sqlda2->sqln = 2; /* 入力変数の数 */

    sqlda2->sqlvar[0].sqltype = ECPGt_char;
    sqlda2->sqlvar[0].sqldata = "postgres";
    sqlda2->sqlvar[0].sqllen  = 8;

    intval = 1;
    sqlda2->sqlvar[1].sqltype = ECPGt_int;
    sqlda2->sqlvar[1].sqldata = (char *)&intval;
    sqlda2->sqlvar[1].sqllen  = sizeof(intval);

After setting up the input SQLDA, open a cursor with the input SQLDA. 入力用SQLDAを設定し終えた後、入力用SQLDAを付けたカーソルを開きます。


    /* Open a cursor with input parameters. */

    /* 入力パラメータ付きでカーソルを開く。 */
    EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

Fetch rows into the output SQLDA from the opened cursor. (Generally, you have to call <command>FETCH</command> repeatedly in the loop, to fetch all rows in the result set.) 開いたカーソルから出力用SQLDA内に行を取り込みます。 (一般的に結果セット内の行をすべて取り込むためには、ループ内でFETCHを繰り返し呼び出さなければなりません。)

    while (1)
    {
        sqlda_t *cur_sqlda;


        /* Assign descriptor to the cursor  */

        /* 記述子をカーソルに割り当てる */
        EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

Next, retrieve the fetched records from the SQLDA, by following the linked list of the <type>sqlda_t</type> structure. 次に、sqlda_t構造体のリンクリストを追うことで、SQLDAから取り込んだレコードを取り出します。

    for (cur_sqlda = sqlda1 ;
         cur_sqlda != NULL ;
         cur_sqlda = cur_sqlda->desc_next)
    {
        ...

Read each columns in the first record. The number of columns is stored in <structfield>sqld</structfield>, the actual data of the first column is stored in <literal>sqlvar[0]</literal>, both members of the <type>sqlda_t</type> structure. 最初のレコードから各列を読み取ります。 列数はsqldに、最初の列の実データはsqlvar[0]に格納されています。 どちらもsqlda_t構造体のメンバです。


        /* Print every column in a row. */

        /* 1行の列をすべて表示する。 */
        for (i = 0; i < sqlda1->sqld; i++)
        {
            sqlvar_t v = sqlda1->sqlvar[i];
            char *sqldata = v.sqldata;
            short sqllen  = v.sqllen;

            strncpy(name_buf, v.sqlname.data, v.sqlname.length);
            name_buf[v.sqlname.length] = '\0';

Now, the column data is stored in the variable <varname>v</varname>. Copy every datum into host variables, looking at <literal>v.sqltype</literal> for the type of the column. ここで、列データがv変数内に格納されました。 列の型についてv.sqltypeを検索しながら、すべてのデータをホスト変数にコピーします。

            switch (v.sqltype) {
                int intval;
                double doubleval;
                unsigned long long int longlongval;

                case ECPGt_char:
                    memset(&var_buf, 0, sizeof(var_buf));
                    memcpy(&var_buf, sqldata, (sizeof(var_buf) <= sqllen ? sizeof(var_buf)-1 : sqllen));
                    break;


                case ECPGt_int: /* integer */

                case ECPGt_int: /* 整数 */
                    memcpy(&intval, sqldata, sqllen);
                    snprintf(var_buf, sizeof(var_buf), "%d", intval);
                    break;

                ...

                default:
                    ...
            }

            printf("%s = %s (type: %d)\n", name_buf, var_buf, v.sqltype);
        }

Close the cursor after processing all of records, and disconnect from the database. すべてのレコードを処理した後カーソルを閉じ、データベースとの接続を切断します。

    EXEC SQL CLOSE cur1;
    EXEC SQL COMMIT;

    EXEC SQL DISCONNECT ALL;

The whole program is shown in <xref linkend="ecpg-sqlda-example-example"/>. プログラム全体を例 36.1に示します。

例36.1 SQLDAプログラムの例

<title>Example SQLDA Program</title>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

EXEC SQL include sqlda.h;


sqlda_t *sqlda1; /* descriptor for output */
sqlda_t *sqlda2; /* descriptor for input */

sqlda_t *sqlda1; /* 出力記述子 */
sqlda_t *sqlda2; /* 入力記述子 */

EXEC SQL WHENEVER NOT FOUND DO BREAK;
EXEC SQL WHENEVER SQLERROR STOP;

int
main(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char query[1024] = "SELECT d.oid,* FROM pg_database d, pg_stat_database s WHERE d.oid=s.datid AND ( d.datname=? OR d.oid=? )";

    int intval;
    unsigned long long int longlongval;
    EXEC SQL END DECLARE SECTION;

    EXEC SQL CONNECT TO uptimedb AS con1 USER uptime;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;

    EXEC SQL PREPARE stmt1 FROM :query;
    EXEC SQL DECLARE cur1 CURSOR FOR stmt1;


    /* Create an SQLDA structure for an input parameter */

    /* 入力パラメータ用のSQLDA構造体を作成する */
    sqlda2 = (sqlda_t *)malloc(sizeof(sqlda_t) + sizeof(sqlvar_t));
    memset(sqlda2, 0, sizeof(sqlda_t) + sizeof(sqlvar_t));

    sqlda2->sqln = 2; /* a number of input variables */

    sqlda2->sqln = 2; /* 入力変数の数 */

    sqlda2->sqlvar[0].sqltype = ECPGt_char;
    sqlda2->sqlvar[0].sqldata = "postgres";
    sqlda2->sqlvar[0].sqllen  = 8;

    intval = 1;
    sqlda2->sqlvar[1].sqltype = ECPGt_int;
    sqlda2->sqlvar[1].sqldata = (char *) &intval;
    sqlda2->sqlvar[1].sqllen  = sizeof(intval);


    /* Open a cursor with input parameters. */

    /* 入力パラメータ付きでカーソルを開く。 */
    EXEC SQL OPEN cur1 USING DESCRIPTOR sqlda2;

    while (1)
    {
        sqlda_t *cur_sqlda;


        /* Assign descriptor to the cursor  */

        /* 記述子をカーソルに割り当てる */
        EXEC SQL FETCH NEXT FROM cur1 INTO DESCRIPTOR sqlda1;

        for (cur_sqlda = sqlda1 ;
             cur_sqlda != NULL ;
             cur_sqlda = cur_sqlda->desc_next)
        {
            int i;
            char name_buf[1024];
            char var_buf[1024];


            /* Print every column in a row. */

            /* 1行の列をすべて表示する。 */
            for (i=0 ; i<cur_sqlda->sqld ; i++)
            {
                sqlvar_t v = cur_sqlda->sqlvar[i];
                char *sqldata = v.sqldata;
                short sqllen  = v.sqllen;

                strncpy(name_buf, v.sqlname.data, v.sqlname.length);
                name_buf[v.sqlname.length] = '\0';

                switch (v.sqltype)
                {
                    case ECPGt_char:
                        memset(&var_buf, 0, sizeof(var_buf));
                        memcpy(&var_buf, sqldata, (sizeof(var_buf)<=sqllen ? sizeof(var_buf)-1 : sqllen) );
                        break;


                    case ECPGt_int: /* integer */

                    case ECPGt_int: /* 整数 */
                        memcpy(&intval, sqldata, sqllen);
                        snprintf(var_buf, sizeof(var_buf), "%d", intval);
                        break;

                    case ECPGt_long_long: /* bigint */
                        memcpy(&longlongval, sqldata, sqllen);
                        snprintf(var_buf, sizeof(var_buf), "%lld", longlongval);
                        break;

                    default:
                    {
                        int i;
                        memset(var_buf, 0, sizeof(var_buf));
                        for (i = 0; i < sqllen; i++)
                        {
                            char tmpbuf[16];
                            snprintf(tmpbuf, sizeof(tmpbuf), "%02x ", (unsigned char) sqldata[i]);
                            strncat(var_buf, tmpbuf, sizeof(var_buf));
                        }
                    }
                        break;
                }

                printf("%s = %s (type: %d)\n", name_buf, var_buf, v.sqltype);
            }

            printf("\n");
        }
    }

    EXEC SQL CLOSE cur1;
    EXEC SQL COMMIT;

    EXEC SQL DISCONNECT ALL;

    return 0;
}

The output of this example should look something like the following (some numbers will vary). この例の出力は以下のようなものになるはずです(一部の数値は変動します)。

oid = 1 (type: 1)
datname = template1 (type: 1)
datdba = 10 (type: 1)
encoding = 0 (type: 5)
datistemplate = t (type: 1)
datallowconn = t (type: 1)
datconnlimit = -1 (type: 5)
datfrozenxid = 379 (type: 1)
dattablespace = 1663 (type: 1)
datconfig =  (type: 1)
datacl = {=c/uptime,uptime=CTc/uptime} (type: 1)
datid = 1 (type: 1)
datname = template1 (type: 1)
numbackends = 0 (type: 5)
xact_commit = 113606 (type: 9)
xact_rollback = 0 (type: 9)
blks_read = 130 (type: 9)
blks_hit = 7341714 (type: 9)
tup_returned = 38262679 (type: 9)
tup_fetched = 1836281 (type: 9)
tup_inserted = 0 (type: 9)
tup_updated = 0 (type: 9)
tup_deleted = 0 (type: 9)

oid = 11511 (type: 1)
datname = postgres (type: 1)
datdba = 10 (type: 1)
encoding = 0 (type: 5)
datistemplate = f (type: 1)
datallowconn = t (type: 1)
datconnlimit = -1 (type: 5)
datfrozenxid = 379 (type: 1)
dattablespace = 1663 (type: 1)
datconfig =  (type: 1)
datacl =  (type: 1)
datid = 11511 (type: 1)
datname = postgres (type: 1)
numbackends = 0 (type: 5)
xact_commit = 221069 (type: 9)
xact_rollback = 18 (type: 9)
blks_read = 1176 (type: 9)
blks_hit = 13943750 (type: 9)
tup_returned = 77410091 (type: 9)
tup_fetched = 3253694 (type: 9)
tup_inserted = 0 (type: 9)
tup_updated = 0 (type: 9)
tup_deleted = 0 (type: 9)