--- /dev/null
+<!-- $PostgreSQL: pgsql/doc/src/sgml/contrib-spi.sgml,v 1.1 2007/12/03 04:18:47 tgl Exp $ -->
+
+<sect1 id="contrib-spi">
+ <title>spi</title>
+
+ <indexterm zone="contrib-spi">
+ <primary>SPI</primary>
+ <secondary>examples</secondary>
+ </indexterm>
+
+ <para>
+ The <filename>contrib/spi</> module provides several workable examples
+ of using SPI and triggers. While these functions are of some value in
+ their own right, they are even more useful as examples to modify for
+ your own purposes. The functions are general enough to be used
+ with any table, but you have to specify table and field names (as described
+ below) while creating a trigger.
+ </para>
+
+ <sect2>
+ <title>refint.c — functions for implementing referential integrity</title>
+
+ <para>
+ <function>check_primary_key()</> and
+ <function>check_foreign_key()</> are used to check foreign key constraints.
+ (This functionality is long since superseded by the built-in foreign
+ key mechanism, of course, but the module is still useful as an example.)
+ </para>
+
+ <para>
+ <function>check_primary_key()</> checks the referencing table.
+ To use, create a BEFORE INSERT OR UPDATE trigger using this
+ function on a table referencing another table. You are to specify
+ as trigger arguments: triggered table column names which correspond
+ to foreign key, referenced table name and column names in referenced
+ table which correspond to primary/unique key. To handle multiple
+ foreign keys, create a trigger for each reference.
+ </para>
+
+ <para>
+ <function>check_foreign_key()</> checks the referenced table.
+ To use, create a BEFORE DELETE OR UPDATE trigger using this
+ function on a table referenced by other table(s). You are to specify
+ as trigger arguments: number of references for which the function has to
+ perform checking, action if referencing key found ('cascade' — to delete
+ corresponding foreign key, 'restrict' — to abort transaction if foreign keys
+ exist, 'setnull' — to set foreign key referencing primary/unique key
+ being deleted to null), triggered table column names which correspond
+ to primary/unique key, then referencing table name and column names
+ corresponding to foreign key (repeated for as many referencing tables/keys
+ as were specified by first argument). Note that the primary/unique key
+ columns should be marked NOT NULL and should have a unique index.
+ </para>
+
+ <para>
+ There are examples in <filename>refint.example</>.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>timetravel.c — functions for implementing time travel</title>
+
+ <para>
+ Long ago, <productname>PostgreSQL</> had a built-in time travel feature
+ that kept the insert and delete times for each tuple. This can be
+ emulated using these functions. To use these functions,
+ you are to add to a table two columns of <type>abstime</> type to store
+ the date when a tuple was inserted (start_date) and changed/deleted
+ (stop_date):
+
+<programlisting>
+CREATE TABLE mytab (
+ ... ...
+ start_date abstime default now(),
+ stop_date abstime default 'infinity'
+ ... ...
+);
+</programlisting>
+
+ So, tuples being inserted with unspecified start_date/stop_date will get
+ the current time in start_date and <literal>infinity</> in
+ stop_date.
+ </para>
+
+ <para>
+ Tuples with stop_date equal to <literal>infinity</> are <quote>valid
+ now</quote>: when trigger will be fired for UPDATE/DELETE of a tuple with
+ stop_date NOT equal to <literal>infinity</> then
+ this tuple will not be changed/deleted!
+ </para>
+
+ <para>
+ If stop_date is equal to <literal>infinity</> then on
+ update only the stop_date in the tuple being updated will be changed (to
+ current time) and a new tuple with new data (coming from SET ... in UPDATE)
+ will be inserted. Start_date in this new tuple will be set to current time
+ and stop_date to <literal>infinity</>.
+ </para>
+
+ <para>
+ A delete does not actually remove the tuple but only set its stop_date
+ to current time.
+ </para>
+
+ <para>
+ To query for tuples <quote>valid now</quote>, include
+ <literal>stop_date = 'infinity'</> in the query's WHERE condition.
+ (You might wish to incorporate that in a view.)
+ </para>
+
+ <para>
+ You can't change start/stop date columns with UPDATE!
+ Use set_timetravel (below) if you need this.
+ </para>
+
+ <para>
+ <function>timetravel()</> is the general trigger function that supports
+ this behavior. Create a BEFORE INSERT OR UPDATE OR DELETE trigger using this
+ function on each time-traveled table. You are to specify two trigger arguments:
+ name of start_date column and name of stop_date column in triggered table.
+ Optionally, you can specify one to three more arguments, which must refer
+ to columns of type <type>text</>. The trigger will store the name of
+ the current user into the first of these columns during INSERT, the
+ second column during UPDATE, and the third during DELETE.
+ </para>
+
+ <para>
+ <function>set_timetravel()</> allows you to turn time-travel on or off for
+ a table.
+ <literal>set_timetravel('mytab', 1)</> will turn TT ON for table mytab.
+ <literal>set_timetravel('mytab', 0)</> will turn TT OFF for table mytab.
+ In both cases the old status is reported. While TT is off, you can modify
+ the start_date and stop_date columns freely.
+ </para>
+
+ <para>
+ <function>get_timetravel()</> returns the TT state for a table without
+ changing it.
+ </para>
+
+ <para>
+ There is an example in <filename>timetravel.example</>.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>autoinc.c — functions for autoincrementing fields</title>
+
+ <para>
+ <function>autoinc()</> is a trigger that stores the next value of
+ a sequence into an integer field. This has some overlap with the
+ built-in <quote>serial column</> feature, but it is not the same:
+ <function>autoinc()</> will override attempts to substitute a
+ different field value during inserts, and optionally it can be
+ used to increment the field during updates, too.
+ </para>
+
+ <para>
+ To use, create a BEFORE INSERT (or optionally BEFORE INSERT OR UPDATE)
+ trigger using this function. You are to specify
+ as trigger arguments: the name of the integer column to be modified,
+ and the name of the sequence object that will supply values.
+ (Actually, you can specify any number of pairs of such names, if
+ you'd like to update more than one autoincrementing column.)
+ </para>
+
+ <para>
+ There is an example in <filename>autoinc.example</>.
+ </para>
+
+ </sect2>
+
+ <sect2>
+ <title>insert_username.c — functions for tracking who changed a table</title>
+
+ <para>
+ <function>insert_username()</> is a trigger that stores the current
+ user's name into a text field. This can be useful for tracking
+ who last modified a particular row within a table.
+ </para>
+
+ <para>
+ To use, create a BEFORE INSERT and/or UPDATE
+ trigger using this function. You are to specify a single trigger
+ argument: the name of the text column to be modified.
+ </para>
+
+ <para>
+ There is an example in <filename>insert_username.example</>.
+ </para>
+
+ </sect2>
+
+ <sect2>
+ <title>moddatetime.c — functions for tracking last modification time</title>
+
+ <para>
+ <function>moddatetime()</> is a trigger that stores the current
+ time into a <type>timestamp</> field. This can be useful for tracking
+ the last modification time of a particular row within a table.
+ </para>
+
+ <para>
+ To use, create a BEFORE UPDATE
+ trigger using this function. You are to specify a single trigger
+ argument: the name of the <type>timestamp</> column to be modified.
+ </para>
+
+ <para>
+ There is an example in <filename>moddatetime.example</>.
+ </para>
+
+ </sect2>
+
+</sect1>
--- /dev/null
+<!-- $PostgreSQL: pgsql/doc/src/sgml/test-parser.sgml,v 1.1 2007/12/03 04:18:47 tgl Exp $ -->
+
+<sect1 id="test-parser">
+ <title>test_parser</title>
+
+ <indexterm zone="test-parser">
+ <primary>test_parser</primary>
+ </indexterm>
+
+ <para>
+ This is an example of a custom parser for full text search.
+ </para>
+
+ <para>
+ It recognizes space-delimited words and returns just two token types:
+
+<programlisting>
+mydb=# SELECT * FROM ts_token_type('testparser');
+ tokid | alias | description
+-------+-------+---------------
+ 3 | word | Word
+ 12 | blank | Space symbols
+(2 rows)
+</programlisting>
+
+ These token numbers have been chosen to be compatible with the default
+ parser's numbering. This allows us to use its <function>headline()</>
+ function, thus keeping the example simple.
+ </para>
+
+ <sect2>
+ <title>Usage</title>
+
+ <para>
+ Running the installation script creates a text search parser
+ <literal>testparser</>. It has no user-configurable parameters.
+ </para>
+
+ <para>
+ You can test the parser with, for example,
+
+<programlisting>
+mydb=# SELECT * FROM ts_parse('testparser', 'That''s my first own parser');
+ tokid | token
+-------+--------
+ 3 | That's
+ 12 |
+ 3 | my
+ 12 |
+ 3 | first
+ 12 |
+ 3 | own
+ 12 |
+ 3 | parser
+</programlisting>
+ </para>
+
+ <para>
+ Real-world use requires setting up a text search configuration
+ that uses the parser. For example,
+
+<programlisting>
+mydb=# CREATE TEXT SEARCH CONFIGURATION testcfg ( PARSER = testparser );
+CREATE TEXT SEARCH CONFIGURATION
+
+mydb=# ALTER TEXT SEARCH CONFIGURATION testcfg
+mydb-# ADD MAPPING FOR word WITH english_stem;
+ALTER TEXT SEARCH CONFIGURATION
+
+mydb=# SELECT to_tsvector('testcfg', 'That''s my first own parser');
+ to_tsvector
+-------------------------------
+ 'that':1 'first':3 'parser':5
+(1 row)
+
+mydb=# SELECT ts_headline('testcfg', 'Supernovae stars are the brightest phenomena in galaxies',
+mydb(# to_tsquery('testcfg', 'star'));
+ ts_headline
+-----------------------------------------------------------------
+ Supernovae <b>stars</b> are the brightest phenomena in galaxies
+(1 row)
+</programlisting>
+ </para>
+
+ </sect2>
+
+</sect1>