diff options
Diffstat (limited to 'doc/src/sgml/pltcl.sgml')
| -rw-r--r-- | doc/src/sgml/pltcl.sgml | 357 |
1 files changed, 179 insertions, 178 deletions
diff --git a/doc/src/sgml/pltcl.sgml b/doc/src/sgml/pltcl.sgml index ed724153bb4..f3b85952dbf 100644 --- a/doc/src/sgml/pltcl.sgml +++ b/doc/src/sgml/pltcl.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 petere Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.23 2003/04/07 01:29:25 petere Exp $ --> <chapter id="pltcl"> @@ -20,10 +20,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 peter trigger procedures. </para> - <para> - This package was originally written by Jan Wieck. - </para> - <!-- **** PL/Tcl overview **** --> <sect1 id="pltcl-overview"> @@ -38,19 +34,19 @@ $Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 peter 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 <function>elog()</>. There is no way to access internals of the - database backend or to gain OS-level access under the permissions of the - <productname>PostgreSQL</productname> user ID, as a C function can do. + database server or to gain OS-level access under the permissions of the + <productname>PostgreSQL</productname> server process, as a C function can do. Thus, any unprivileged database user may be permitted to use this language. </para> <para> - The other, implementation restriction is that Tcl procedures cannot + The other, implementation restriction is that Tcl functions cannot be used to create input/output functions for new data types. </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 <application>PL/Tcl</> called <literal>PL/TclU</> + to safe Tcl. For example, one might want a Tcl function that sends + email. To handle these cases, there is a variant of <application>PL/Tcl</> called <literal>PL/TclU</> (for untrusted Tcl). This is the exact same language except that a full Tcl interpreter is used. <emphasis>If <application>PL/TclU</> is used, it must be installed as an untrusted procedural language</emphasis> so that only @@ -66,7 +62,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 peter library directory if Tcl/Tk support is specified in the configuration step of the installation procedure. To install <application>PL/Tcl</> and/or <application>PL/TclU</> in a particular database, use the - <filename>createlang</filename> script, for example + <command>createlang</command> program, for example <literal>createlang pltcl <replaceable>dbname</></literal> or <literal>createlang pltclu <replaceable>dbname</></literal>. </para> @@ -74,58 +70,59 @@ $Header: /cvsroot/pgsql/doc/src/sgml/pltcl.sgml,v 2.22 2002/09/21 18:32:53 peter <!-- **** PL/Tcl description **** --> - <sect1 id="pltcl-description"> - <title>Description</title> - - <sect2> + <sect1 id="pltcl-functions"> <title>PL/Tcl Functions and Arguments</title> <para> - To create a function in the <application>PL/Tcl</> language, use the standard syntax + To create a function in the <application>PL/Tcl</> language, use the standard syntax: - <programlisting> +<programlisting> CREATE FUNCTION <replaceable>funcname</replaceable> (<replaceable>argument-types</replaceable>) RETURNS <replaceable>return-type</replaceable> AS ' # PL/Tcl function body -' LANGUAGE 'pltcl'; - </programlisting> +' LANGUAGE pltcl; +</programlisting> - <application>PL/TclU</> is the same, except that the language should be specified as + <application>PL/TclU</> is the same, except that the language has to be specified as <literal>pltclu</>. </para> <para> The body of the function is simply a piece of Tcl script. When the function is called, the argument values are passed as - variables <literal>$1</literal> ... <literal>$n</literal> to the + variables <literal>$1</literal> ... <literal>$<replaceable>n</replaceable></literal> to the Tcl script. The result is returned from the Tcl code in the usual way, with a <literal>return</literal> - statement. For example, a function + statement. + </para> + + <para> + For example, a function returning the greater of two integer values could be defined as: - <programlisting> -CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS ' +<programlisting> +CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS ' if {$1 > $2} {return $1} return $2 -' LANGUAGE 'pltcl' WITH (isStrict); - </programlisting> +' LANGUAGE pltcl STRICT; +</programlisting> - Note the clause <literal>WITH (isStrict)</>, which saves us from - having to think about NULL input values: if a NULL is passed, the - function will not be called at all, but will just return a NULL + Note the clause <literal>STRICT</>, which saves us from + having to think about null input values: if a null value is passed, the + function will not be called at all, but will just return a null result automatically. </para> <para> - In a non-strict function, - if the actual value of an argument is NULL, the corresponding - <literal>$n</literal> variable will be set to an empty string. - To detect whether a particular argument is NULL, use the function + In a nonstrict function, + if the actual value of an argument is null, the corresponding + <literal>$<replaceable>n</replaceable></literal> variable will be set to an empty string. + To detect whether a particular argument is null, use the function <literal>argisnull</>. For example, suppose that we wanted <function>tcl_max</function> - with one null and one non-null argument to return the non-null - argument, rather than NULL: + with one null and one nonnull argument to return the nonnull + argument, rather than null: - <programlisting> -CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS ' +<programlisting> +CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS ' if {[argisnull 1]} { if {[argisnull 2]} { return_null } return $2 @@ -133,8 +130,8 @@ CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS ' if {[argisnull 2]} { return $1 } if {$1 > $2} {return $1} return $2 -' LANGUAGE 'pltcl'; - </programlisting> +' LANGUAGE pltcl; +</programlisting> </para> <para> @@ -145,15 +142,19 @@ CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS ' </para> <para> - Composite-type arguments are passed to the procedure as Tcl arrays. - The element names of the array are the attribute names of the composite - type. If an attribute in the passed 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>PostgreSQL</productname> documentation) in PL/Tcl: - - <programlisting> -CREATE FUNCTION overpaid_2 (EMP) RETURNS bool AS ' + Composite-type arguments are passed to the function as Tcl + arrays. The element names of the array are the attribute names + of the composite type. If an attribute in the passed row has the + null value, it will not appear in the array. Here is an example: + +<programlisting> +CREATE TABLE employee ( + name text, + salary integer, + age integer +); + +CREATE FUNCTION overpaid(employee) RETURNS boolean AS ' if {200000.0 < $1(salary)} { return "t" } @@ -161,110 +162,109 @@ CREATE FUNCTION overpaid_2 (EMP) RETURNS bool AS ' return "t" } return "f" -' LANGUAGE 'pltcl'; - </programlisting> +' LANGUAGE pltcl; +</programlisting> </para> <para> - There is not currently any support for returning a composite-type + There is currently no support for returning a composite-type result value. </para> - </sect2> + </sect1> - <sect2> + <sect1 id="pltcl-data"> <title>Data Values in PL/Tcl</title> <para> - The argument values supplied to a PL/Tcl function's script are simply + The argument values supplied to a PL/Tcl function's code are simply the input arguments converted to text form (just as if they had been - displayed by a SELECT statement). Conversely, the <literal>return</> + displayed by a <command>SELECT</> statement). Conversely, the <literal>return</> command will accept any string that is acceptable input format for the function's declared return type. So, the PL/Tcl programmer can manipulate data values as if they were just text. </para> - </sect2> + </sect1> - <sect2> + <sect1 id="pltcl-global"> <title>Global Data in PL/Tcl</title> <para> Sometimes it - is useful to have some global status data that is held between two - calls to a procedure or is shared between different procedures. + is useful to have some global data that is held between two + calls to a function or is shared between different functions. This is easily done since - all PL/Tcl procedures executed in one backend share the same + all PL/Tcl functions executed in one session share the same safe Tcl interpreter. So, any global Tcl variable is accessible to - all PL/Tcl procedure calls, and will persist for the duration of the - SQL client connection. (Note that <application>PL/TclU</> functions likewise share + all PL/Tcl function calls and will persist for the duration of the + SQL session. (Note that <application>PL/TclU</> functions likewise share global data, but they are in a different Tcl interpreter and cannot communicate with PL/Tcl functions.) </para> <para> - To help protect PL/Tcl procedures from unintentionally interfering + To help protect PL/Tcl functions from unintentionally interfering with each other, a global - array is made available to each procedure via the <function>upvar</> - command. The global name of this variable is the procedure's internal - name and the local name is <literal>GD</>. It is recommended that + array is made available to each function via the <function>upvar</> + command. The global name of this variable is the function's internal + name, and the local name is <literal>GD</>. It is recommended that <literal>GD</> be used - for private status data of a procedure. Use regular Tcl global variables + for private data of a function. Use regular Tcl global variables only for values that you specifically intend to be shared among multiple - procedures. + functions. </para> <para> An example of using <literal>GD</> appears in the <function>spi_execp</function> example below. </para> - </sect2> + </sect1> - <sect2> + <sect1 id="pltcl-dbaccess"> <title>Database Access from PL/Tcl</title> <para> The following commands are available to access the database from - the body of a PL/Tcl procedure: - </para> + the body of a PL/Tcl function: <variablelist> <varlistentry> - <term><function>spi_exec</function> <literal>?-count <replaceable>n</replaceable>? ?-array <replaceable>name</replaceable>? <replaceable>query</replaceable> ?<replaceable>loop-body</replaceable>?</literal></term> + <term><function>spi_exec</function> <literal>?-count <replaceable>n</replaceable>? ?-array <replaceable>name</replaceable>? <replaceable>command</replaceable> ?<replaceable>loop-body</replaceable>?</literal></term> <listitem> <para> - Execute an SQL query given as a string. An error in the query - causes an error to be raised. Otherwise, the command's return value + Executes an SQL command given as a string. An error in the command + causes an error to be raised. Otherwise, the return value of <function>spi_exec</function> is the number of rows processed (selected, inserted, updated, or - deleted) by the query, or zero if the query is a utility - statement. In addition, if the query is a SELECT statement, the + deleted) by the command, or zero if the command is a utility + statement. In addition, if the command is a <command>SELECT</> statement, the values of the selected columns are placed in Tcl variables as described below. </para> <para> The optional <literal>-count</> value tells <function>spi_exec</function> the maximum number of rows - to process in the query. The effect of this is comparable to - setting up the query as a cursor and then saying <literal>FETCH n</>. + to process in the command. The effect of this is comparable to + setting up a query as a cursor and then saying <literal>FETCH <replaceable>n</></>. </para> <para> - If the query is a <literal>SELECT</> statement, the values of the statement's + If the command is a <command>SELECT</> statement, the values of the result columns are placed into Tcl variables named after the columns. If the <literal>-array</> option is given, the column values are - instead stored into the named associative array, with the SELECT + instead stored into the named associative array, with the column names used as array indexes. </para> <para> - If the query is a SELECT statement and no <replaceable>loop-body</> + If the command is a <command>SELECT</> statement and no <replaceable>loop-body</> script is given, then only the first row of results are stored into - Tcl variables; remaining rows, if any, are ignored. No store occurs + Tcl variables; remaining rows, if any, are ignored. No storing occurs if the - SELECT returns no rows (this case can be detected by checking the - result of <function>spi_exec</function>). For example, + query returns no rows. (This case can be detected by checking the + result of <function>spi_exec</function>.) For example, - <programlisting> +<programlisting> spi_exec "SELECT count(*) AS cnt FROM pg_proc" - </programlisting> +</programlisting> will set the Tcl variable <literal>$cnt</> to the number of rows in the <structname>pg_proc</> system catalog. @@ -272,23 +272,23 @@ spi_exec "SELECT count(*) AS cnt FROM pg_proc" <para> If the optional <replaceable>loop-body</> argument is given, it is a piece of Tcl script that is executed once for each row in the - SELECT result (note: <replaceable>loop-body</> is ignored if the given - query is not a SELECT). The values of the current row's fields + query result. (<replaceable>loop-body</> is ignored if the given + command is not a <command>SELECT</>.) The values of the current row's columns are stored into Tcl variables before each iteration. For example, - <programlisting> +<programlisting> spi_exec -array C "SELECT * FROM pg_class" { elog DEBUG "have table $C(relname)" } - </programlisting> +</programlisting> - will print a DEBUG log message for every row of pg_class. This + will print a log message for every row of <literal>pg_class</>. This feature works similarly to other Tcl looping constructs; in particular <literal>continue</> and <literal>break</> work in the usual way inside the loop body. </para> <para> - If a field of a SELECT result is NULL, the target + If a column of a query result is null, the target variable for it is <quote>unset</> rather than being set. </para> </listitem> @@ -299,18 +299,18 @@ spi_exec -array C "SELECT * FROM pg_class" { <listitem> <para> Prepares and saves a query plan for later execution. The saved plan - will be retained for the life of the current backend. + will be retained for the life of the current session. </para> <para> - The query may use <firstterm>arguments</>, which are placeholders for + The query may use parameters, that is, placeholders for values to be supplied whenever the plan is actually executed. - In the query string, refer to arguments - by the symbols <literal>$1</literal> ... <literal>$n</literal>. - If the query uses arguments, the names of the argument types + In the query string, refer to parameters + by the symbols <literal>$1</literal> ... <literal>$<replaceable>n</replaceable></literal>. + If the query uses parameters, the names of the parameter types must be given as a Tcl list. (Write an empty list for - <replaceable>typelist</replaceable> if no arguments are used.) - Presently, the argument types must be identified by the internal - type names shown in pg_type; for example <literal>int4</> not + <replaceable>typelist</replaceable> if no parameters are used.) + Presently, the parameter types must be identified by the internal + type names shown in the system table <literal>pg_type</>; for example <literal>int4</> not <literal>integer</>. </para> <para> @@ -325,24 +325,24 @@ spi_exec -array C "SELECT * FROM pg_class" { <term><function>spi_execp</> <literal>?-count <replaceable>n</replaceable>? ?-array <replaceable>name</replaceable>? ?-nulls <replaceable>string</replaceable>? <replaceable>queryid</replaceable> ?<replaceable>value-list</replaceable>? ?<replaceable>loop-body</replaceable>?</literal></term> <listitem> <para> - Execute a query previously prepared with <function>spi_prepare</>. + Executes a query previously prepared with <function>spi_prepare</>. <replaceable>queryid</replaceable> is the ID returned by - <function>spi_prepare</>. If the query references arguments, - a <replaceable>value-list</replaceable> must be supplied: this - is a Tcl list of actual values for the arguments. This must be - the same length as the argument type list previously given to + <function>spi_prepare</>. If the query references parameters, + a <replaceable>value-list</replaceable> must be supplied. This + is a Tcl list of actual values for the parameters. The list must be + the same length as the parameter type list previously given to <function>spi_prepare</>. Omit <replaceable>value-list</replaceable> - if the query has no arguments. + if the query has no parameters. </para> <para> The optional value for <literal>-nulls</> is a string of spaces and <literal>'n'</> characters telling <function>spi_execp</function> - which of the arguments are null values. If given, it must have exactly the + which of the parameters are null values. If given, it must have exactly the same length as the <replaceable>value-list</replaceable>. If it - is not given, all the argument values are non-NULL. + is not given, all the parameter values are nonnull. </para> <para> - Except for the way in which the query and its arguments are specified, + Except for the way in which the query and its parameters are specified, <function>spi_execp</> works just like <function>spi_exec</>. The <literal>-count</>, <literal>-array</>, and <replaceable>loop-body</replaceable> options are the same, @@ -351,7 +351,7 @@ spi_exec -array C "SELECT * FROM pg_class" { <para> Here's an example of a PL/Tcl function using a prepared plan: - <programlisting> +<programlisting> CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS ' if {![ info exists GD(plan) ]} { # prepare the saved plan on the first call @@ -361,14 +361,14 @@ CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS ' } spi_execp -count 1 $GD(plan) [ list $1 $2 ] return $cnt -' LANGUAGE 'pltcl'; - </programlisting> +' LANGUAGE pltcl; +</programlisting> Note that each backslash that Tcl should see must be doubled when we type in the function, since the main parser processes - backslashes too in CREATE FUNCTION. We need backslashes inside + backslashes, too, in <command>CREATE FUNCTION</>. We need backslashes inside the query string given to <function>spi_prepare</> to ensure that - the <literal>$n</> markers will be passed through to + the <literal>$<replaceable>n</replaceable></> markers will be passed through to <function>spi_prepare</> as-is, and not replaced by Tcl variable substitution. </para> @@ -383,8 +383,8 @@ CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS ' <listitem> <para> Returns the OID of the row inserted by the last - <function>spi_exec</>'d or <function>spi_execp</>'d query, - if that query was a single-row INSERT. (If not, you get zero.) + <function>spi_exec</> or <function>spi_execp</>, + if the command was a single-row <command>INSERT</>. (If not, you get zero.) </para> </listitem> </varlistentry> @@ -395,18 +395,18 @@ CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS ' <para> Duplicates all occurrences of single quote and backslash characters in the given string. This may be used to safely quote strings - that are to be inserted into SQL queries given + that are to be inserted into SQL commands given to <function>spi_exec</function> or <function>spi_prepare</function>. - For example, think about a query string like + For example, think about an SQL command string like <programlisting> "SELECT '$val' AS ret" </programlisting> - where the Tcl variable val actually contains + where the Tcl variable <literal>val</> actually contains <literal>doesn't</literal>. This would result - in the final query string + in the final command string <programlisting> SELECT 'doesn't' AS ret @@ -415,21 +415,21 @@ SELECT 'doesn't' AS ret which would cause a parse error during <function>spi_exec</function> or <function>spi_prepare</function>. - The submitted query should contain + The submitted command should contain <programlisting> SELECT 'doesn''t' AS ret </programlisting> - which can be formed in PL/Tcl as + which can be formed in PL/Tcl using <programlisting> "SELECT '[ quote $val ]' AS ret" </programlisting> One advantage of <function>spi_execp</function> is that you don't - have to quote argument values like this, since the arguments are never - parsed as part of an SQL query string. + have to quote parameter values like this, since the parameters are never + parsed as part of an SQL command string. </para> </listitem> </varlistentry> @@ -441,26 +441,27 @@ SELECT 'doesn''t' AS ret <term><function>elog</> <replaceable>level</replaceable> <replaceable>msg</replaceable></term> <listitem> <para> - Emit a log or error message. Possible levels are + Emits a log or error message. Possible levels are <literal>DEBUG</>, <literal>LOG</>, <literal>INFO</>, <literal>NOTICE</>, <literal>WARNING</>, <literal>ERROR</>, and <literal>FATAL</>. Most simply emit the given message just like - the <literal>elog</> backend C function. <literal>ERROR</> + the <literal>elog</> C function. <literal>ERROR</> raises an error condition: further execution of the function is abandoned, and the current transaction is aborted. <literal>FATAL</> aborts the transaction and causes the current - backend to shut down (there is probably no good reason to use + session to shut down. (There is probably no good reason to use this error level in PL/Tcl functions, but it's provided for - completeness). + completeness.) </para> </listitem> </varlistentry> </variablelist> + </para> - </sect2> + </sect1> - <sect2> + <sect1 id="pltcl-trigger"> <title>Trigger Procedures in PL/Tcl</title> <indexterm> @@ -469,8 +470,8 @@ SELECT 'doesn''t' AS ret </indexterm> <para> - Trigger procedures can be written in PL/Tcl. As is customary in - <productname>PostgreSQL</productname>, a procedure that's to be called + Trigger procedures can be written in PL/Tcl. + <productname>PostgreSQL</productname> requires that a procedure that is to be called as a trigger must be declared as a function with no arguments and a return type of <literal>trigger</>. </para> @@ -481,16 +482,16 @@ SELECT 'doesn''t' AS ret <variablelist> <varlistentry> - <term><replaceable class="Parameter">$TG_name</replaceable></term> + <term><varname>$TG_name</varname></term> <listitem> <para> - The name of the trigger from the CREATE TRIGGER statement. + The name of the trigger from the <command>CREATE TRIGGER</command> statement. </para> </listitem> </varlistentry> <varlistentry> - <term><replaceable class="Parameter">$TG_relid</replaceable></term> + <term><varname>$TG_relid</varname></term> <listitem> <para> The object ID of the table that caused the trigger procedure @@ -500,20 +501,20 @@ SELECT 'doesn''t' AS ret </varlistentry> <varlistentry> - <term><replaceable class="Parameter">$TG_relatts</replaceable></term> + <term><varname>$TG_relatts</varname></term> <listitem> <para> - A Tcl list of the table field names, prefixed with an empty list - element. So looking up an element name in the list with <application>Tcl</>'s + A Tcl list of the table column names, prefixed with an empty list + element. So looking up a column name in the list with <application>Tcl</>'s <function>lsearch</> command returns the element's number starting - with 1 for the first column, the same way the fields are customarily + with 1 for the first column, the same way the columns are customarily numbered in <productname>PostgreSQL</productname>. </para> </listitem> </varlistentry> <varlistentry> - <term><replaceable class="Parameter">$TG_when</replaceable></term> + <term><varname>$TG_when</varname></term> <listitem> <para> The string <literal>BEFORE</> or <literal>AFTER</> depending on the @@ -523,7 +524,7 @@ SELECT 'doesn''t' AS ret </varlistentry> <varlistentry> - <term><replaceable class="Parameter">$TG_level</replaceable></term> + <term><varname>$TG_level</varname></term> <listitem> <para> The string <literal>ROW</> or <literal>STATEMENT</> depending on the @@ -533,44 +534,46 @@ SELECT 'doesn''t' AS ret </varlistentry> <varlistentry> - <term><replaceable class="Parameter">$TG_op</replaceable></term> + <term><varname>$TG_op</varname></term> <listitem> <para> - The string <literal>INSERT</>, <literal>UPDATE</> or + The string <literal>INSERT</>, <literal>UPDATE</>, or <literal>DELETE</> depending on the type of trigger call. </para> </listitem> </varlistentry> <varlistentry> - <term><replaceable class="Parameter">$NEW</replaceable></term> + <term><varname>$NEW</varname></term> <listitem> <para> - An associative array containing the values of the new table row for - INSERT/UPDATE actions, or empty for DELETE. The array is indexed - by field name. Fields that are NULL will not appear in the array! + An associative array containing the values of the new table + row for <command>INSERT</> or <command>UPDATE</> actions, or + empty for <command>DELETE</>. The array is indexed by column + name. Columns that are null will not appear in the array. </para> </listitem> </varlistentry> <varlistentry> - <term><replaceable class="Parameter">$OLD</replaceable></term> + <term><varname>$OLD</varname></term> <listitem> <para> - An associative array containing the values of the old table row for - UPDATE/DELETE actions, or empty for INSERT. The array is indexed - by field name. Fields that are NULL will not appear in the array! + An associative array containing the values of the old table + row for <command>UPDATE</> or <command>DELETE</> actions, or + empty for <command>INSERT</>. The array is indexed by column + name. Columns that are null will not appear in the array. </para> </listitem> </varlistentry> <varlistentry> - <term><replaceable class="Parameter">$args</replaceable></term> + <term><varname>$args</varname></term> <listitem> <para> A Tcl list of the arguments to the procedure as given in the - CREATE TRIGGER statement. These arguments are also accessible as - <literal>$1</literal> ... <literal>$n</literal> in the procedure body. + <command>CREATE TRIGGER</command> statement. These arguments are also accessible as + <literal>$1</literal> ... <literal>$<replaceable>n</replaceable></literal> in the procedure body. </para> </listitem> </varlistentry> @@ -582,22 +585,22 @@ SELECT 'doesn''t' AS ret The return value from a trigger procedure can be one of the strings <literal>OK</> or <literal>SKIP</>, or a list as returned by the <literal>array get</> Tcl command. If the return value is <literal>OK</>, - the operation (INSERT/UPDATE/DELETE) that fired the trigger will proceed + the operation (<command>INSERT</>/<command>UPDATE</>/<command>DELETE</>) that fired the trigger will proceed normally. <literal>SKIP</> tells the trigger manager to silently suppress the operation for this row. If a list is returned, it tells PL/Tcl to return a modified row to the trigger manager that will be inserted - instead of the one given in $NEW (this works for INSERT/UPDATE - only). Needless to say that all this is only meaningful when the trigger - is BEFORE and FOR EACH ROW; otherwise the return value is ignored. + instead of the one given in <varname>$NEW</>. (This works for <command>INSERT</> and <command>UPDATE</> + only.) Needless to say that all this is only meaningful when the trigger + is <literal>BEFORE</> and <command>FOR EACH ROW</>; otherwise the return value is ignored. </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: + incremented on every update operation. - <programlisting> -CREATE FUNCTION trigfunc_modcount() RETURNS TRIGGER AS ' +<programlisting> +CREATE FUNCTION trigfunc_modcount() RETURNS trigger AS ' switch $TG_op { INSERT { set NEW($1) 0 @@ -611,24 +614,24 @@ CREATE FUNCTION trigfunc_modcount() RETURNS TRIGGER AS ' } } return [array get NEW] -' LANGUAGE 'pltcl'; +' LANGUAGE pltcl; CREATE TABLE mytab (num integer, description text, modcnt integer); CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab FOR EACH ROW EXECUTE PROCEDURE trigfunc_modcount('modcnt'); - </programlisting> +</programlisting> Notice that the trigger procedure itself does not know the column name; that's supplied from the trigger arguments. This lets the - trigger procedure be re-used with different tables. + trigger procedure be reused with different tables. </para> - </sect2> + </sect1> - <sect2> - <title> Modules and the <function>unknown</> command</title> + <sect1 id="pltcl-unknown"> + <title>Modules and the <function>unknown</> command</title> <para> - PL/Tcl has support for auto-loading Tcl code when used. + PL/Tcl has support for autoloading Tcl code when used. It recognizes a special table, <literal>pltcl_modules</>, which is presumed to contain modules of Tcl code. If this table exists, the module <literal>unknown</> is fetched from the table @@ -638,7 +641,7 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab <para> While the <literal>unknown</> module could actually contain any initialization script you need, it normally defines a Tcl - <quote>unknown</> procedure that is invoked whenever Tcl does + <function>unknown</> procedure that is invoked whenever Tcl does not recognize an invoked procedure name. <application>PL/Tcl</>'s standard version of this procedure tries to find a module in <literal>pltcl_modules</> that will define the required procedure. If one is found, it is @@ -653,7 +656,7 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab support scripts to maintain these tables: <command>pltcl_loadmod</>, <command>pltcl_listmod</>, <command>pltcl_delmod</>, as well as source for the standard - unknown module <filename>share/unknown.pltcl</>. This module + <literal>unknown</> module in <filename>share/unknown.pltcl</>. This module must be loaded into each database initially to support the autoloading mechanism. </para> @@ -662,9 +665,9 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab must be readable by all, but it is wise to make them owned and writable only by the database administrator. </para> - </sect2> + </sect1> - <sect2> + <sect1 id="pltcl-procnames"> <title>Tcl Procedure Names</title> <para> @@ -674,16 +677,14 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab differ. Tcl, however, requires all procedure names to be distinct. PL/Tcl deals with this by making the internal Tcl procedure names contain the object - ID of the procedure's <structname>pg_proc</> row as part of their name. Thus, + ID of the function from the system table <structname>pg_proc</> as part of their name. Thus, <productname>PostgreSQL</productname> functions with the same name - and different argument types will be different Tcl procedures too. This + and different argument types will be different Tcl procedures, too. This is not normally a concern for a PL/Tcl programmer, but it might be visible when debugging. </para> - </sect2> - - </sect1> + </sect1> </chapter> <!-- Keep this comment at the end of the file |
