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記述子領域はSELECT
、FETCH
、DESCRIBE
文の結果を処理する、より洗練された手法です。
SQL記述子領域は1行のデータをメタデータ項目と一緒に1つのデータ構造体としてグループ化します。
特に動的SQL文を実行する場合は結果列の性質が前もってわかりませんので、メタデータが有用です。
PostgreSQLは記述子領域を使用するための2つの方法、名前付きSQL記述子領域とC構造化SQLDA、を提供します。
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. <!-- The scope of the allocated descriptor is WHAT?. --> 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記述子領域を生成します。
34.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 DESCRIPTORname
: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つだけ定義されています。
これは、記述子領域に存在する項目数を表すものです
(つまり、結果内に含まれる列数です)。
このホスト変数はinteger型でなければなりません。
項目記述子領域からフィールドを取り出すには、以下のコマンドを使用します。
EXEC SQL GET DESCRIPTORname
VALUEnum
: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>.
TYPE
が9
の場合、DATETIME_INTERVAL_CODE
は、DATE
では1
、TIME
では2
、TIMESTAMP
では3
、TIME WITH TIME ZONE
では4
、TIMESTAMP 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:
EXECUTE
、DECLARE
およびOPEN
文では、INTO
およびUSING
の効果は異なります。
また、問い合わせやカーソル用の入力パラメータを提供するために記述子領域は手作業で構築することができます。
USING SQL DESCRIPTOR
は入力パラメータとパラメータ付きの問い合わせに渡す方法です。
名前付きSQL記述子領域を構築するSQL文は以下の通りです。
name
EXEC SQL SET DESCRIPTORname
VALUEnum
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;
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
キーワードが省略されていることに注意してください。
34.7.1のINTO
および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>問い合わせをプリペアし、そのカーソルを宣言します。
結果セット用のSQLDAを宣言します。
入力パラメータ用のSQLDAを宣言し、初期化(メモリ割り当て、パラメータの設定)します。
入力用SQLDAでカーソルを開きます。
カーソルから行を取り出し、出力用SQLDAに格納します。
出力用SQLDAから値をホスト変数に(必要に応じて変換を行い)読み取ります。
カーソルを閉じます。
入力用SQLDAに割り当てられたメモリ領域を解放します。
SQLDA uses three data structure
types: <type>sqlda_t</type>, <type>sqlvar_t</type>,
and <type>struct sqlname</type>.
SQLDAはsqlda_t
、sqlvar_t
、struct 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の理解のより良い助けになるでしょう。
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
キーワードを使用してOPEN
、DECLARE
、EXECUTE
文に渡される場合、ここにはパラメータ付き問い合わせの入力パラメータ数が含まれます。
SELECT
、EXECUTE
、FETCH
文の出力として使用される場合、この値は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. これは結果セット内の列の配列です。
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.h
のenum 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"/>. データそのものを指し示します。 データ書式は34.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. フィールドの名前です。
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: フィールドの意味は以下の通りです。
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>結果セットを受けとるためのsqlda_t
構造体を宣言します。
宣言したSQLDAを指定した問い合わせを処理するためにFETCH
/EXECUTE
/DESCRIBE
を実行します。
sqlda_t
構造体のメンバsqln
を検索することにより結果セット内のレコード数を検査します。
sqlda_t
構造体のメンバsqlvar[0]
、sqlvar[1]
などから各列の値を入手します。
sqlda_t
構造体のメンバdesc_next
ポインタを追い、次の行(sqlda_t
構造体)に進みます。
必要なだけ上を繰り返します。
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;
...
}
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>プリペアド問い合わせ(プリペアド文)を作成します。
入力用SQLDAとしてsqlda_t構造体を宣言します。
入力用SQLDA用にメモリ領域を(sqlda_t構造体として)割り当てます。
割り当てたメモリに入力値を設定(コピー)します。
入力用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"
とinteger型を持つ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);
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
構造体内のsqltype
、sqldata
、sqllen
に格納します。
/* 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"/>. プログラム全体を例 34.1に示します。
例34.1 SQLDAプログラムの例
#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) dathasloginevt = f (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) dathasloginevt = f (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)