<!--
$Header: /usr/prj/pg/cvsroot/doc/doc/src/sgml/pltcl.sgml,v 1.7 2001/08/23 05:31:48 i-kaori Exp $
-->

 <chapter id="pltcl">
  <!--<title>PL/Tcl - TCL Procedural Language</title>-->
  <title>PL/Tcl――TCL手続型言語</title>
<indexterm><primary>PL/Tcl</primary></indexterm><indexterm><primary>PostgreSQL</primary><secondary>PL/Tcl</secondary></indexterm><indexterm><primary sortas="げんご">言語</primary><secondary>PL/Tcl</secondary></indexterm><indexterm><primary>Tcl</primary></indexterm>
  <para>
   <!--PL/Tcl is a loadable procedural language for the
   <productname>Postgres</productname> database system
   that enables the Tcl language to be used to create functions and
   trigger procedures.-->

   PL/Tclとは、<productname>Postgres</productname>データベースシステムにロード可能な手続型言語で、Tcl言語を使った関数とトリガプロシージャを作成できます。
  </para>

  <para>
   <!--This package was originally written by Jan Wieck .-->
    このパッケージのオリジナルは、Jan Wieckによって書かれました。
  </para>

  <!-- **** PL/Tcl overview **** -->

  <sect1 id="pltcl-overview">
   <title><!--Overview-->概要</title>

   <para>
    <!--PL/Tcl offers most of the capabilities a function
    writer has in the C language, except for some restrictions.-->

    PL/Tclでは、数点の制約を除いて、C言語で書かれた関数と同じような能力のものを提供します。

   </para>
   <para>
    <!--The good restriction is that everything is executed in a safe
    Tcl interpreter. In addition to the limited command set of safe Tcl, only
    a few commands are available to access the database via SPI and to raise
    messages via elog(). There is no way to access internals of the
    database backend or to gain OS-level access under the permissions of the
    <productname>Postgres</productname> user ID, as a C function can do.
    Thus, any unprivileged database user may be
    permitted to use this language.-->

    すべては安全なTclインタープリタで実行されていて、それはよい制約だといえます。安全なTclの制約付きのコマンドセットに、SPIを使ってデータベースに接続するコマンドと、elog()を使ってメッセージを処理するためのコマンドなどの、わずかなコマンドが追加されています。C関数では可能ですが、Tclでは、データベースのバックエンド内部に接続する方法や、<productname>Postgres</productname>のユーザーレベルの権限で、OSレベルの接続を行う方法はありません。また、データベースの権限がないユーザーはこの言語を使用することはできません。

   </para>
   <para>
    <!--The other, implementation restriction is that Tcl procedures cannot
    be used to create input/output functions for new data types.-->

    その他実装上の制約としては、Tclの手続では新しいデータ型のための入出力関数を作成することはできないことがあります。

   </para>
   <para>
    <!--Sometimes it is desirable to write Tcl functions that are not restricted
    to safe Tcl - for example, one might want a Tcl function that sends
    mail.  To handle these cases, there is a variant of PL/Tcl called PL/TclU
    (for untrusted Tcl).  This is the exact same language except that a full
    Tcl interpreter is used.  <emphasis>If PL/TclU is used, it must be
    installed as an untrusted procedural language</emphasis> so that only
    database superusers can create functions in it.  The writer of a PL/TclU
    function must take care that the function cannot be used to do anything
    unwanted, since it will be able to do anything that could be done by
    a user logged in as the database administrator.-->

    安全なTclに制約されないTcl関数を書くことが望ましい場合があります。たとえば、メールを送るTcl関数が必要な場合などでは、PL/TclU（安全ではないTcl）のような、異なるPL/Tclがあります。これは、完全なTclインタープリターが使用されているという点以外の違いはありません。<emphasis>PL/TclUを使用する場合は、信用されていない手続き型言語としてインストールさせる必要があります。</emphasis>そうすることによって、データベースの管理者のみが関数を作成することができるようになります。PL/TclU関数の作者は、データベース管理者としてログインしたユーザーができるあらゆることの実行が可能となるので、その関数が意図されたこと以外のことを行わないように細心の注意を払う必要があります。

   </para>
   <para>
    <!--The shared object for the PL/Tcl and PL/TclU call handlers is
    automatically built and installed in the
    <productname>Postgres</productname> 
    library directory if Tcl/Tk support is specified
    in the configuration step of the installation procedure.  To install
    PL/Tcl and/or PL/TclU in a particular database, use the
    <filename>createlang</filename> script.-->

    Tcl/Tkサポートがインストールの設定の際に指定されていれば、PL/TclとPL/TclUコールハンドラの共有オブジェクトは自動的に<productname>Postgres</productname>のライブラリディレクトリに構築されます。PL/Tcl、またはPL/TclUを特定のデータベースにインストールしたい場合は<filename>createlang</filename>を利用してください。
   </para>
  </sect1>

  <!-- **** PL/Tcl description **** -->

  <sect1 id="pltcl-description">
   <title><!--Description-->説明</title>

   <sect2>
    <title><productname>Postgres</productname><!--Functions and Tcl Procedure Names-->の関数とTclプロシージャ名
    </title>
<indexterm><primary>PL/Tcl</primary><secondary sortas="かんすう">関数</secondary></indexterm><indexterm><primary sortas="かんすう">関数</primary><secondary>PL/Tcl</secondary></indexterm>
    <para>
     <!--In <productname>Postgres</productname>, one and the 
     same function name can be used for
     different functions as long as the number of arguments or their types
     differ. This would collide with Tcl procedure names. To offer the same
     flexibility in PL/Tcl, the internal Tcl procedure names contain the object
     ID of the procedure's pg_proc row as part of their name. Thus, different
     argtype versions of the same <productname>Postgres</productname> 
     function are different for Tcl too.-->

     <productname>Postgres</productname>では、その関数の引数の数と引数の型が異なっていれば、同じ関数名を使用することが可能です。これはTclのプロシージャ名の付け方と対立します。PL/Tclでも同じような柔軟性を持たせるために、内部のTcl関数名には、pg_procプロシージャ行のオブジェクトIDが関数名の一部として含まれています。したがって、同じ<productname>Postgres</productname>のTclにおいても、異なった引数型を持つ関数は異なった関数とみなされます。
    </para>

   </sect2>

   <sect2>
    <title><!--Defining Functions in PL/Tcl-->PL/Tcl関数定義</title>

    <para>
     <!--To create a function in the PL/Tcl language, use the standard syntax-->
     PL/Tclで関数を定義する際には、下記の標準構文を使用してください。<indexterm><primary>CREATE FUNCTION</primary></indexterm><indexterm><primary>SQL</primary><secondary>CREATE FUNCTION</secondary></indexterm>
</para>

<programlisting>
CREATE FUNCTION <replaceable>funcname</replaceable> (<replaceable>argument-types</replaceable>) RETURNS <replaceable>return-type</replaceable> AS '
    # PL/Tcl function body
' LANGUAGE 'pltcl';
</programlisting>

<para>
     <!--When the function is called, the arguments are given as
     variables <literal>$1</literal> ... <literal>$n</literal> to the
     Tcl procedure body.  The result is returned
     from the Tcl code in the usual way, with a <literal>return</literal>
     statement.  For example, a function
     returning the higher of two int4 values could be defined as:-->

     関数が呼ばれたとき、引数は変数<literal>$1</literal> ... <literal>$n</literal>のようにして、Tclのプロシージャ本体に渡されます。結果はTclのコードから通常のように<literal>return</literal>文で返されます。たとえば、2つのint4型の値で、大きい方を返すものを定義するには、下記のようにします。
</para>

<programlisting>
CREATE FUNCTION tcl_max (int4, int4) RETURNS int4 AS '
    if {$1 > $2} {return $1}
    return $2
' LANGUAGE 'pltcl';
</programlisting>

<para>
     <!--To return a NULL value from a PL/Tcl function, execute
     <literal>return_null</literal>.-->
     PL/Tcl関数からNULLを返す場合には<literal>return_null</literal>を使用します。
    </para>

    <para>
     <!--Composite type arguments are given to the procedure as Tcl arrays.
     The element names
     in the array are the attribute names of the composite
     type. If an attribute in the actual row
     has the NULL value, it will not appear in the array! Here is
     an example that defines the overpaid_2 function (as found in the
     older <productname>Postgres</productname> documentation) in PL/Tcl-->

     複合型引数は、配列としてTclプロシージャに引き渡されます。配列の要素名は複合型の属性名となります。実際の行で属性がNULLが入っていた場合には配列には表示されません。下記はPL/Tclで書かれたoverpaid_2関数（支払われすぎ関数、この例は古い<productname>Postgres</productname>にも記載されています）の例です。
</para>

<programlisting>
CREATE FUNCTION overpaid_2 (EMP) RETURNS bool AS '
    if {200000.0 < $1(salary)} {
        return "t"
    }
    if {$1(age) < 30 &amp;&amp; 100000.0 < $1(salary)} {
        return "t"
    }
    return "f"
' LANGUAGE 'pltcl';
</programlisting>

   </sect2>

   <sect2>
    <title><!--Global Data in PL/Tcl-->PL/Tclのグローバルデータ</title>
<indexterm><primary>PL/Tcl</primary><secondary sortas="ぐろーばるでーた">グローバルでーた</secondary></indexterm>
    <para>
     <!--Sometimes (especially when using the SPI functions described later) it
     is useful to have some global status data that is held between two
     calls to a procedure.  This is easily done since
     all PL/Tcl procedures executed in one backend share the same
     safe Tcl interpreter.-->

     特に後述するSPI関数を使用する場合などは、2つのプロシージャ間で保持されるグローバルステータスデータを使用すると便利な場合があります。1つのバックエンドから発行されたすべてのPL/Tclプロシージャは、同じTclインタープリタを使用するので、容易に設定することができます。
    </para>
    <para>
     <!--To help protect PL/Tcl procedures from unwanted side effects,
     an array is made available to each procedure via the upvar
     command. The global name of this variable is the procedure's internal
     name and the local name is GD.  It is recommended that GD be used
     for private status data of a procedure.  Use regular Tcl global variables
     only for values that you specifically intend to be shared among multiple
     procedures.-->

     PL/Tclプロシージャが予期しない作動に巻き込まれないようにするために、upvarコマンドを使用することによって、各関数は配列を使用することができます。この変数のグローバル名はプロシージャの内部名で、ローカル名はGDとなります。プロシージャのプライベートステータスデータではGDを利用することをお勧めします。複数のプロシージャで共有させる値の場合のみ、通常のTclのグローバル変数を使用してください。<indexterm><primary>upvar</primary></indexterm><indexterm><primary>PL/Tcl</primary><secondary>upvar</secondary></indexterm>
    </para>
   </sect2>

   <sect2>
    <title><!--Trigger Procedures in PL/Tcl-->PL/Tclのトリガプロシージャ</title>
<indexterm><primary>PL/Tcl</primary><secondary sortas="とりがぷろしーじゃ">トリガプロシージャ</secondary></indexterm><indexterm><primary sortas="とりが">トリガ</primary><secondary>PL/Tcl</secondary></indexterm>

    <para>
     <!--Trigger procedures are defined in <productname>Postgres</productname>
     as functions without
     arguments and a return type of opaque. And so are they in the PL/Tcl
     language.-->

     トリガ機能は、<productname>Postgres</productname>で引数のない、opaque型を返す関数と定義されています。PL/Tclでも同様です。
    </para>
    <para>
     <!--The information from the trigger manager is given to the procedure body
     in the following variables:-->

     トリガプロシージャからの情報は下記の変数を使用して関数本体に引き渡されます。
</para>

     <variablelist>

      <varlistentry>
       <term><replaceable class="Parameter">$TG_name</replaceable></term>
       <listitem>
	<para>
	 <!--The name of the trigger from the CREATE TRIGGER statement.-->
         CREATE TRIGGER文でのトリガ名
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$TG_relid</replaceable></term>
       <listitem>
	<para>
	 <!--The object ID of the table that caused the trigger procedure
	 to be invoked.-->

         トリガ機能を発行させた、テーブルのオブジェクトID
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$TG_relatts</replaceable></term>
       <listitem>
	<para>
	 <!--A Tcl list of the tables field names prefixed with an empty list element.
	 So looking up an element name in the list with the lsearch Tcl command
	 returns the same positive number starting from 1 as the fields are numbered
	 in the pg_attribute system catalog.-->

         前に空のリスト要素が付いた、テーブルのフィールド名のTclリスト。したがって、lsearch Tclコマンドを使って要素名をリストから検索した場合には、同じ正の数が返されます。それは、pg_attributeシステムカタログのフィールドが番号付けされているのと同様に1から始まります
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$TG_when</replaceable></term>
       <listitem>
	<para>
	 <!--The string BEFORE or AFTER depending on the event of the trigger call.-->
         BEFOREまたはAFTERの文字列。トリガの呼び出しによって変動します
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$TG_level</replaceable></term>
       <listitem>
	<para>
	 <!--The string ROW or STATEMENT depending on the event of the trigger call.-->
         ROWまたはSTATEMENTの文字列。トリガの呼び出しによって変動します
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$TG_op</replaceable></term>
       <listitem>
	<para>
	 <!--The string INSERT, UPDATE or DELETE depending on the event of the 
	 trigger call.-->
         INSERT、UPDATE、DELETEの文字列。トリガの呼び出しによって変動します
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$NEW</replaceable></term>
       <listitem>
	<para>
	 <!--An array containing the values of the new table row on INSERT/UPDATE
	 actions, or empty on DELETE.-->
         INSERT/UPDATEが行われたテーブルの行の新しい値、またはDELETEされた空の行の場合には空の配列
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$OLD</replaceable></term>
       <listitem>
	<para>
	 <!--An array containing the values of the old table row on UPDATE/DELETE
	 actions, or empty on INSERT.-->
         INSERT/UPDATEが行われたテーブルの行の古い値、またはINSERTされたの行の場合には空の配列
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$GD</replaceable></term>
       <listitem>
	<para>
	 <!--The global status data array as described above.-->
         上記で説明のあったグローバルステータスデータの配列
	</para>
       </listitem>
      </varlistentry>

      <varlistentry>
       <term><replaceable class="Parameter">$args</replaceable></term>
       <listitem>
	<para>
	 <!--A Tcl list of the arguments to the procedure as given in the
	 CREATE TRIGGER statement. The arguments are also accessible as $1 ... $n
	 in the procedure body.-->
         CREATE TRIGGER文で指定された関数の引数のTclリスト。引数は関数内では、$1 ... $nとして使用可能です
	</para>
       </listitem>
      </varlistentry>

     </variablelist>

    <para>
     <!--The return value from a trigger procedure is one of the strings OK or SKIP,
     or a list as returned by the 'array get' Tcl command. If the return value
     is OK, the normal operation (INSERT/UPDATE/DELETE) that fired this trigger
     will take place. Obviously, SKIP tells the trigger manager to silently
     suppress the operation. The list from 'array get' tells PL/Tcl
     to return a modified row to the trigger manager that will be inserted instead
     of the one given in $NEW (INSERT/UPDATE only). Needless to say that all
     this is only meaningful when the trigger is BEFORE and FOR EACH ROW.-->

     トリガプロシージャからの返り値はOK、SKIPの文字列、Tclコマンドarray getで返されたリストのどれかになります。返り値がOKの場合は、このトリガを発行した通常の操作（INSERT/UPDATE/DELETE）が処理を引き継ぎます。SKIPの場合は、トリガ管理に作業を終了するように指示します。INSERT/UPDATEでのarray getによって返されたリストは、PL/Tclに対し、$NEWで指定されたものの代わりに挿入される、変更された行をトリガマネージャに返すように促します。いうまでもありませんが、これらすべてはトリガがBEFORE、またはFOR EACH ROWで行われたときに有効となります。
    </para>
    <para>
     <!--Here's a little example trigger procedure that forces an integer value
     in a table to keep track of the number of updates that are performed on the
     row. For new rows inserted, the value is initialized to 0 and then
     incremented on every update operation:-->

     以下に、行に行われた更新回数をテーブル内の整数値に保持させるトリガプロシージャの例を示します。新しく行が挿入された場合、初期値は0となり、更新が行われるたびに1ずつ増えていきます。
</para>

<programlisting>
CREATE FUNCTION trigfunc_modcount() RETURNS OPAQUE AS '
    switch $TG_op {
        INSERT {
            set NEW($1) 0
        }
        UPDATE {
            set NEW($1) $OLD($1)
            incr NEW($1)
        }
        default {
            return OK
        }
    }
    return [array get NEW]
' LANGUAGE 'pltcl';

CREATE TABLE mytab (num int4, modcnt int4, description text);

CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
    FOR EACH ROW EXECUTE PROCEDURE trigfunc_modcount('modcnt');
</programlisting>

   </sect2>

   <sect2>
    <title><!--Database Access from PL/Tcl-->PL/Tclからのデータベース接続</title>
<indexterm><primary>PL/Tcl</primary><secondary sortas="でーたべーすせつぞく">データベース接続</secondary></indexterm><indexterm><primary sortas="でーたべーす">データベース</primary><secondary sortas="PL/Tclからのせつぞく">PL/Tclからの接続</secondary></indexterm>
    <para>
     <!--The following commands are available to access the database from
     the body of a PL/Tcl procedure:-->
     下記のコマンドは、PL/Tclプロシージャ内からデータベースへの接続を行う場合に使用できるコマンドです。
    </para>

    <variablelist>

     <varlistentry>
      <term>elog <replaceable>level</replaceable> <replaceable>msg</replaceable><indexterm><primary>elog</primary></indexterm><indexterm><primary>PL/Tcl</primary><secondary sortas="かんすう">関数</secondary><tertiary>elog</tertiary></indexterm><indexterm><primary sortas="かんすう">関数</primary><secondary>elog</secondary></indexterm></term>
      <listitem>
       <para>
	<!--Fire a log message. Possible levels are NOTICE, ERROR,
	FATAL, DEBUG and NOIND
	as for the <function>elog</function> C function.-->
        ログメッセージを発行します。Cの<function>elog</function>関数と同様に可能なレベルはNOTICE、ERROR、FATAL、DEBUG、NOINDです。
       </para>
      </listitem>
     </varlistentry>

     <varlistentry>
      <term>quote <replaceable>string</replaceable><indexterm><primary>quote</primary></indexterm><indexterm><primary>PL/Tcl</primary><secondary sortas="かんすう">関数</secondary><tertiary>quote</tertiary></indexterm><indexterm><primary sortas="かんすう">関数</primary><secondary>quote</secondary></indexterm></term>
      <listitem>
       <para>
	<!--Duplicates all occurrences of single quote and backslash characters.
	It should be used when variables are used in the query string given
	to <function>spi_exec</function> or
	<function>spi_prepare</function> (not for the value list on
	<function>spi_execp</function>).
	Think about a query string like-->

        すべての一重引用符とバックスラッシュに対してそれらを2重にします。これは、<function>spi_exec</function>、または<function>spi_prepare</function>（<function>spi_execp</function>の値リストでは不可）に引き渡される問い合わせ文字列で変数が使用されている場合に使用します。下記のような問い合わせ文字列を考えてみましょう。
</para>

<programlisting>
"SELECT '$val' AS ret"
</programlisting>

<para>
	<!--where the Tcl variable val actually contains "doesn't". This would result
	in the final query string-->
        この問い合わせ文字列で、Tcl変数valに実際は「doesn't」が入っている場合、最終問い合わせ文字列は、以下のようになります。
</para>

<programlisting>
"SELECT 'doesn't' AS ret"
</programlisting>

<para>
	<!--which would cause a parse error during
	<function>spi_exec</function> or
	<function>spi_prepare</function>.
	It should contain-->

        これでは、<function>spi_exec</function>や<function>spi_prepare</function>を実行している際にエラーとなってしまいます。本来は以下のようになっているべきです。
</para>

<programlisting>
"SELECT 'doesn''t' AS ret"
</programlisting>

<para>
	<!--and has to be written as-->つまり、以下のように書かれているべきです。
</para>

<programlisting>
"SELECT '[ quote $val ]' AS ret"
</programlisting>

      </listitem>
     </varlistentry>

     <varlistentry>
      <term>spi_exec ?-count <replaceable>n</replaceable>? ?-array <replaceable>name</replaceable>? <replaceable>query</replaceable> ?<replaceable>loop-body</replaceable>?<indexterm><primary>spi_exec</primary></indexterm><indexterm><primary>PL/Tcl</primary><secondary sortas="かんすう">関数</secondary><tertiary>spi_exec</tertiary></indexterm><indexterm><primary sortas="かんすう">関数</primary><secondary>spi_exec</secondary></indexterm></term>
      <listitem>
       <para>
	<!--Call parser/planner/optimizer/executor for query.
	The optional -count value tells <function>spi_exec</function>
	the maximum number of rows
	to be processed by the query.-->

        問い合わせでパーサー（parser）/プランナ（planner）/オプティマイザ（optimizer）/エクゼキュータ（executor）を呼びます。オプション-countの値は<function>spi_exec</function>に、問い合わせで実行する最大行数を指定します。
       </para>
       <para>
	<!--If the query is
	a SELECT statement and the optional loop-body (a body of Tcl commands
	like in a foreach statement) is given, it is evaluated for each
	row selected and behaves like expected on continue/break. The values
	of selected fields are put into variables named as the column names. So a-->

        問い合わせがSELECT文で、loop-bodyオプション（foreach文のような、Tclコマンドの本体）が与えられていた場合、選択された各行を1つ1つ評価し、continue/breakで期待されているように振る舞います。選択されたフィールドの値は、列名として変数に格納されます。したがって、以下のような場合には、変数$cntにpg_procシステムカタログにある行数を格納します。
</para>

<programlisting>
spi_exec "SELECT count(*) AS cnt FROM pg_proc"
</programlisting>

<para>
	<!--will set the variable $cnt to the number of rows in the pg_proc system
	catalog. If the option -array is given, the column values are stored
	in the associative array named 'name' indexed by the column name
	instead of individual variables.-->

        -arrayオプションが与えられた場合には、列名は'name'という連想した配列に格納され、各変数ではなく、列名がインデックスに使用されます。以下のものは、各pg_class行のDEBUGログメッセージを表示させます。
</para>

<programlisting>
spi_exec -array C "SELECT * FROM pg_class" {
    elog DEBUG "have table $C(relname)"
}
</programlisting>

<para>
	<!--will print a DEBUG log message for every row of pg_class. The return value
	of <function>spi_exec</function> is the number of rows
	affected by the query as found in
	the global variable SPI_processed.-->
        <function>spi_exec</function>の返り値はグローバル変数SPI_processedにあるような、問い合わせによって変更する行の数です。
       </para>
      </listitem>
     </varlistentry>

     <varlistentry>
      <term>spi_prepare <replaceable>query</replaceable> <replaceable>typelist</replaceable><indexterm><primary>spi_prepare</primary></indexterm><indexterm><primary>PL/Tcl</primary><secondary sortas="かんすう">関数</secondary><tertiary>spi_prepare</tertiary></indexterm><indexterm><primary sortas="かんすう">関数</primary><secondary>spi_prepare</secondary></indexterm></term>
      <listitem>
       <para>
	<!--Prepares AND SAVES a query plan for later execution. It is a bit different
	from the C level SPI_prepare in that the plan is automatically copied to the
	toplevel memory context. Thus, there is currently no way of preparing a
	plan without saving it.-->

        後の実行のためにAND SAVES問い合わせ計画を用意してください。計画が自動的にメモリコンテキストのトップレベルにコピーされる点で、CレベルのSPI_prepareとは少々異なります。したがって、現時点では保持せずに計画を用意することはできません。
       </para>
       <para>
	<!--If the query references arguments, the type names must be given as a Tcl
	list. The return value from spi_prepare is a query ID to be used in
	subsequent calls to spi_execp. See spi_execp for a sample.-->

        問い合わせが引数を参照する場合、必ず型名はTclリストとして渡される必要があります。spi_prepareは問い合わせIDを返し、それはspi_execpへと続く、後の問い合わせで使用されます。例はspi_execpを参照してください。
       </para>
      </listitem>
     </varlistentry>

     <varlistentry>
      <term>spi_exec ?-count <replaceable>n</replaceable>? ?-array<replaceable>name</replaceable>? ?-nulls<replaceable>string</replaceable>? <replaceable>queryid</replaceable> ?<replaceable>value-list</replaceable>? ?<replaceable>loop-body</replaceable>?<indexterm><primary>spi_exec</primary></indexterm><indexterm><primary>PL/Tcl</primary><secondary sortas="かんすう">関数</secondary><tertiary>spi_exec</tertiary></indexterm><indexterm><primary sortas="かんすう">関数</primary><secondary>spi_exec</secondary></indexterm></term>
      <listitem>
       <para>
	<!--Execute a prepared plan from spi_prepare with variable substitution.
	The optional -count value tells spi_execp the maximum number of rows
	to be processed by the query.-->

        spi_prepareによって用意された計画を変数に置き換えて実行します。オプション-countの値は、spi_execpに対して、問い合わせで実行する最大行数を指定します。
       </para>
       <para>
	<!--The optional value for -nulls is a string of spaces and 'n' characters
	telling spi_execp which of the values are NULL's. If given, it must
	have exactly the length of the number of values.-->

        オプション-nullsの値は、スペースと「n」文字で構成された文字列で、spi_execpに、どの値がNULLであるかを指定します。与えられた場合は、値の数と一致する数である必要があります。
       </para>
       <para>
	<!--The queryid is the ID returned by the spi_prepare call.-->
        queryidとは、spi_prepare呼び出しによって返されたIDです。
       </para>
       <para>
	<!--If there was a typelist given to spi_prepare, a Tcl list of values of
	exactly the same length must be given to spi_execp after the query. If
	the type list on spi_prepare was empty, this argument must be omitted.-->

        spi_prepareに対して型リストが渡された場合、問い合わせの後に、Tclリストの値と一致する長さのものをspi_execpに渡す必要があります。spi_prepareの型リストが空だった場合、この引数は省略する必要があります。
        
       </para>
       <para>
	<!--If the query is a SELECT statement, the same as described for spi_exec
	happens for the loop-body and the variables for the fields selected.-->
        問い合わせがSELECT文であった場合、loop-bodyと選択されたフィールドの変数については、spi_exec同じ現象が起こります。
       </para>
       <para>
	<!--Here's an example for a PL/Tcl function using a prepared plan:-->
        下記は、PL/Tcl関数が用意された計画を使用する例です。
</para>

<programlisting>
CREATE FUNCTION t1_count(int4, int4) RETURNS int4 AS '
    if {![ info exists GD(plan) ]} {
        # prepare the saved plan on the first call
        set GD(plan) [ spi_prepare &bsol;&bsol;
                "SELECT count(*) AS cnt FROM t1 WHERE num &gt;= &bsol;&bsol;$1 AND num &lt;= &bsol;&bsol;$2" &bsol;&bsol;
                int4 ]
    }
    spi_execp -count 1 $GD(plan) [ list $1 $2 ]
    return $cnt
' LANGUAGE 'pltcl';
</programlisting>

<para>
	<!--Note that each backslash that Tcl should see must be doubled in
	the query creating the function, since the main parser processes
	backslashes too on CREATE FUNCTION.
	Inside the query string given to spi_prepare should
	really be dollar signs to mark the parameter positions and to not let
	$1 be substituted by the value given in the first function call.-->

        Tclが認識すべき各バックスラッシュは、CREATE FUNCTIONでもバックスラッシュを生成するため、関数を作成している問い合わせでは2重に表記する必要があります。spi_prepareに引き渡される問い合わせ文字列の中では、引数の箇所を印すためと、$1に最初の関数の呼び出しで与えられた値で置き換わらないようにするためにドル記号を記述するべきです。

       </para>
      </listitem>
     </varlistentry>

     <varlistentry>
      <term>
       <!--Modules and the unknown command-->
       モジュールと不明なコマンド
      </term>
      <listitem>
       <para>
	<!--PL/Tcl has a special support for things often used. It recognizes two
	magic tables, pltcl_modules and pltcl_modfuncs.
	If these exist, the module 'unknown' is loaded into the interpreter
	right after creation. Whenever an unknown Tcl procedure is called,
	the unknown proc is asked to check if the procedure is defined in one
	of the modules. If this is true, the module is loaded on demand.
	To enable this behavior, the PL/Tcl call handler must be compiled
	with -DPLTCL_UNKNOWN_SUPPORT set.-->

        PL/Tclには、使用頻度の高いものに対して特別なサポートが用意されています。それは、pltcl_modulesとpltcl_modfuncsという、2つの特別な「魔法」のテーブルを認識します。これらが存在する場合、「不明な」モジュールは、作成された直後にインタープリタに組み込まれます。不明なTclプロシージャが呼び出された場合にはいつでも、そのプロシージャがモジュールの中で定義されているかの確認を不明プロシージャにさせます。その結果が真であれば、モジュールは要求どおりに組み込まれます。この動作を実行するには、-DPLTCL_UNKNOWN_SUPPORTセットと一緒にPL/Tclコールハンドラがコンパイルされている必要があります。
       </para>
       <para>
	<!--There are support scripts to maintain these tables in the modules
	subdirectory of the PL/Tcl source including the source for the
	unknown module that must get installed initially.-->

        これらのテーブルを管理するサポートスクリプトは、始めからインストールされている必要のある不明なモジュールのソースと一緒に、PL/Tclソースのmodulesサブディレクトリにあります。
       </para>
      </listitem>
     </varlistentry>

    </variablelist>

   </sect2>

  </sect1>
 </chapter>

<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"./reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->
