]> granicus.if.org Git - postgresql/commitdiff
Information completely translated to the SGML/DocBook source files
authorThomas G. Lockhart <lockhart@fourpalms.org>
Sun, 5 Apr 1998 17:10:41 +0000 (17:10 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Sun, 5 Apr 1998 17:10:41 +0000 (17:10 +0000)
 pgtcl.sgml, spi.sgml, trigger.sgml.
Online docs in html and postscript are the current versions.

doc/libpgtcl.doc [deleted file]
doc/spi.txt [deleted file]
doc/trigger.txt [deleted file]

diff --git a/doc/libpgtcl.doc b/doc/libpgtcl.doc
deleted file mode 100644 (file)
index 1ce0276..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-
-pgtcl is a tcl package for front-end programs to interface with PostgreSQL
-backends.    PgTcl does not use the libpq library but communicates to
-the backend directly via the frontend-backend protocol.  Thus, it is
-more efficient than previous postgres->tcl bindings which are layered
-on top of libpq.  In addition, pgtcl can handle multiple backend
-connections from a single frontend application.
-
-If you have any questions or bug reports, please send them to
-Jolly Chen at jolly@cs.berkeley.edu.
-
--------------------------------------------------------------------
-
-
-The pgtcl package provides the following commands. 
-
-       pg_connect      - opens a connection to the backend server
-       pg_disconnect   - closes a connection
-       pg_exec         - send a query to the backend
-       pg_select       - loop over the result of a select statement
-       pg_result       - manipulate the results of a query
-
-       pg_lo_creat     - create a large object
-       pg_lo_open      - open a large object
-       pg_lo_close     - close a large object
-       pg_lo_read      - read a large object
-       pg_lo_write     - write a large object
-       pg_lo_lseek     - seek to a position on a large object
-       pg_lo_tell      - return the current seek position of a large object
-       pg_lo_unlink    - delete a large object
-       pg_lo_import    - import a Unix file into a large object
-       pg_lo_export    - export a large object into a Unix file
-
-1)  pg_connect:   opens a connection to the backend
-
-   syntax:
-        pg_connect dbName [-host hostName] [-port portNumber] [-tty pqtty] [-options optionalBackendArgs]]
-
-   the return result is either an error message or a handle for a database
-   connection.  Handles start with the prefix "pgp"
-
-
-2)  pg_disconnect:     closes a connection
-
-   syntax:
-        pg_disconnect connection
-
-   The argument passed in must be a connection pointer.
-
-3)  pg_exec:           send a query string to the backend 
-
-   syntax:
-       pg_exec connection query
-
-   the return result is either an error message or a handle for a query
-   result.  Handles start with the prefix "pgp"
-
-4)     pg_select:              loop over the result of a select statement
-
-   syntax:
-       pg_select connection query var proc
-
-   The query must be a select statement.  Anything else returns an error.
-   The var variable is an array name used in the loop.  It is filled
-   out with the result of the query for each tuple using the field
-   names as the associative indeces.  Proc is the procedure that is
-   run for each tuple found.
-
-   example: (DB is set to database name)
-       set conn [pg_connect $DB]
-       pg_select $conn "SELECT * from table" array {
-               puts [format "%5d %s" array(control) array(name)]
-       }
-       pg_disconnect $conn
-
-5)  pg_result:         get information about a query result
-
-   syntax:
-        pg_result result ?option? 
-              
-    the options are:
-         -status  
-             the status of the result
-        -oid
-             if the last query was an insert, returns the oid of the 
-             inserted tuple
-        -conn
-             the connection that produced the result
-        -assign arrayName
-             assign the results to an array
-        -numTuples
-             the number of tuples in the query
-        -attributes
-             returns a list of the name/type pairs of the tuple attributes
-        -getTuple tupleNumber
-             returns the values of the tuple in a list
-        -clear 
-             clear the result buffer. Do not reuse after this
-
-----------------------------------------------------------------------------
-The pg_lo* routines are interfaces to the Inversion large objects in postgres.
-The functions are designed to mimic the analogous file system functions in
-the standard Unix file system interface.
-
-The pg_lo* routines should typically be used within a BEGIN/END transaction
-block becaus the file descriptor returned by pg_lo_open is only valid for
-the current transaction.  pg_lo_import and pg_lo_export MUST be used
-in a BEGIN/END transaction block.
-
-* pg_lo_creat:         create a large object
-
- syntax:
-       g_lo_creat conn mode
-
-mode can be any OR'ing together of INV_READ, INV_WRITE, and INV_ARCHIVE. 
-The OR delimiter character is "|".
-       e.g. [pg_lo_creat $conn "INV_READ|INV_WRITE"]
-
-returns the oid of the large object created.
-
-* pg_lo_open:          open a large object
-
- syntax:
-        pg_lo_open conn objOid mode 
-
- where mode can be either "r", "w", or "rw"
-
- returns a file descriptor for use in later pg_lo* routines
-
-* pg_lo_close:         close a large object
-
- syntax:
-        pg_lo_close conn fd 
-
-* pg_lo_read:          read a large object
-
- syntax:
-       pg_lo_read conn fd bufVar len
-
-reads at most len bytes from a large object into a variable named bufVar.
-Note that the third argument should be a variable name.
-
-* pg_lo_write:         write a large object
-
- syntax:
-       pg_lo_write conn fd buf len
-
-write at most len bytes to a large object.  
-The third argument should be the actual string to write, not a variable name.
-
-* pg_lo_lseek:         seek to a position on a large object
-
- syntax:
-       pg_lo_lseek conn fd offset whence
-
-whence can be "SEEK_CUR", "SEEK_END", or "SEEK_SET"
-
-* pg_lo_tell:          return the current seek position of a large object
-
- syntax:
-       pg_lo_tell conn fd
-
-* pg_lo_unlink:                delete a large object 
-
- syntax:
-       pg_lo_unlink conn lobjId
-
-* pg_lo_import:                import a Unix file into a large object
-
- syntax:
-       pg_lo_import conn filename
-
-  pg_lo_import must be called within a BEGIN/END transaction block
-
-* pg_lo_export:                export a large object into a Unix file
- syntax:
-       pg_lo_export conn lobjId filename
-
-  pg_lo_export must be called within a BEGIN/END transaction block
-
-------------------------------------------------------------------
-Here's a small example of how to use the routines:
-
-# getDBs :
-#   get the names of all the databases at a given host and port number
-#   with the defaults being the localhost and port 5432
-#   return them in alphabetical order
-proc getDBs { {host "localhost"} {port "5432"} } {
-    # datnames is the list to be result
-    set conn [pg_connect template1 -host $host -port $port]
-    set res [pg_exec $conn "SELECT datname FROM pg_database ORDER BY datname"]
-    set ntups [pg_result $res -numTuples]
-    for {set i 0} {$i < $ntups} {incr i} {
-       lappend datnames [pg_result $res -getTuple $i]
-    }
-    pg_disconnect $conn
-    return $datnames
-}
-
diff --git a/doc/spi.txt b/doc/spi.txt
deleted file mode 100644 (file)
index fe6d602..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-
-               PostgreSQL Server Programming Interface
-
-   The Server Programming Interface (SPI) is an attempt to give users the
-ability to run SQL-queries inside user-defined C-functions.  Given the lack
-of a proper Procedural Language (PL) in the current version of PostgreSQL,
-SPI is only way to write server stored procedures and triggers.  In the future
-SPI will be used as the "workhorse" for PL.
-
-   In fact, SPI is just set of builtin interface functions to simplify
-access to the Parser, Planner, Optimizer and Executor. SPI also does some
-memory management.
-
-   To avoid misunderstanding we'll use the word "function" for SPI interface
-functions and the word "procedure" for user-defined C-functions using SPI.
-
-   SPI procedures are always called by some (upper) Executor and the SPI
-manager uses the Executor to run your queries. Other procedures may be
-called by the Executor running queries from your procedure.
-
-   Note, that if during execution of a query from a procedure the transaction
-is be aborted then control will not be returned to your procedure - all work
-will be rolled back and the server will wait for the next command from the
-client.  This will be changed in the future versions.
-
-   Other restrictions are the inability to execute BEGIN, END and ABORT
-(transaction control statements) and cursor operations.  This will also be
-changed in future.
-
-
-                         Interface functions
-
-   If successful, SPI functions return a non-negative result (either via
-returned (int) value or in SPI_result global variable, as described below).
-On error, a negative result will be returned.
-
-
-int SPI_connect (void)
-
-   Connects your procedure to the SPI manager.  Initializes the SPI internal
-   structures for query execution and memory management.
-   
-   You should call this function if you will need to execute queries. Some
-   utility SPI functions may be called from un-connected procedures.
-
-   Returns:
-
-   SPI_OK_CONNECT if connected.
-
-   SPI_ERROR_CONNECT if not. You may get this error if SPI_connect() is
-   called from an already connected procedure - e.g. if you directly call one
-   procedure from another connected one.  Actually, while the child procedure
-   will be able to use SPI, your parent procedure will not be able to continue
-   to use SPI after the child returns (if SPI_finish() is called by the child).
-   It's bad practice.
-
-
-int SPI_finish(void)
-
-   Disconnects your procedure from the SPI manager and frees all memory
-   allocations made by your procedure via palloc() since the SPI_connect(). 
-   These allocations can't be used any more! See Memory management.
-
-   After SPI_finish() is called your procedure loses the ability to run
-   queries.  The server is in the same state as just before the call to
-   SPI_connect().
-
-   Returns:
-
-   SPI_OK_FINISH if properly disconnected.
-   SPI_ERROR_UNCONNECTED if called from an un-connected procedure. No problem
-   with this - it means that nothing was made by the SPI manager.
-
-   NOTE! SPI_finish() MUST be called by connected procedure or you may get
-   unpredictable results! But you are able to skip the call to SPI_finish()
-   if you abort the transaction (via elog(WARN)).
-
-
-int SPI_exec(char *query, int tcount)
-
-   Creates an execution plan (parser+planner+optimizer) and executes query
-   for tcount tuples.  This should only be called from a connected procedure.
-   If tcount eq 0 then it executes the query for all tuples returned by the
-   query scan. Using tcount > 0 you may restrict the number of tuples for
-   which the query will be executed:
-
-   SPI_exec ("insert into _table_ select * from _table_", 5);
-
-   - at max 5 tuples will be inserted into _table_.
-
-   If execution of your query was successful then one of the following
-   (non-negative) values will be returned:
-
-   SPI_OK_UTILITY if some utility (e.g. CREATE TABLE ...) was executed.
-   SPI_OK_SELECT if SELECT (but not SELECT ... INTO!) was executed.
-   SPI_OK_SELINTO if SELECT ... INTO was executed.
-   SPI_OK_INSERT if INSERT (or INSERT ... SELECT) was executed.
-   SPI_OK_DELETE if DELETE was executed.
-   SPI_OK_UPDATE if UPDATE was executed.
-
-   NOTE! You may pass many queries in one string or query string may be
-   re-written by RULEs. SPI_exec() returns the result for the last query
-   executed.
-
-   The actual number of tuples for which the (last) query was executed is
-   returned in the global variable SPI_processed (if not SPI_OK_UTILITY).
-
-   If SPI_OK_SELECT returned and SPI_processed > 0 then you may use global
-   pointer SPITupleTable *SPI_tuptable to access the selected tuples:
-
-   Structure SPITupleTable is defined in spi.h:
-
-   typedef struct
-   {
-       uint32      alloced;        /* # of alloced vals */
-       uint32      free;           /* # of free vals */
-       TupleDesc   tupdesc;        /* tuple descriptor */
-       HeapTuple  *vals;           /* tuples */
-   } SPITupleTable;
-
-   HeapTuple *vals is an array of pointers to tuples. TupleDesc tupdesc is
-   a tuple descriptor which you may pass to SPI functions dealing with
-   tuples.
-
-   NOTE! Functions SPI_exec(), SPI_execp() and SPI_prepare() change both
-   SPI_processed and SPI_tuptable (just the pointer, not the contents of the
-   structure)!  So, save them in local procedure variables if you need them.
-
-   Also NOTE, that SPI_finish() frees and makes all SPITupleTables
-   unusable! (See Memory management).
-
-   SPI_exec() may return one of the following (negative) values:
-
-   SPI_ERROR_ARGUMENT if query is NULL or tcount < 0.
-   SPI_ERROR_UNCONNECTED if procedure is unconnected.
-   SPI_ERROR_COPY if COPY TO/FROM stdin.
-   SPI_ERROR_CURSOR if DECLARE/CLOSE CURSOR, FETCH.
-   SPI_ERROR_TRANSACTION if BEGIN/ABORT/END.
-   SPI_ERROR_OPUNKNOWN if type of query is unknown (this shouldn't occur).
-
-
-void *SPI_prepare(char *query, int nargs, Oid * argtypes)
-
-   Creates and returns an execution plan (parser+planner+optimizer) but doesn't
-   execute the query. Should only be called from a connected procedure.
-
-   nargs is number of parameters ($1 ... $<nargs> - as in SQL-functions),
-   *argtypes is an array of parameter type OIDs.
-
-   nargs may be 0 only if there is not any $1 in query.
-
-   Execution of prepared execution plans is sometimes much faster so this
-   feature may be useful if the same query will be executed many times.
-
-   NOTE!  The plan returned by SPI_prepare() may be used only in current
-   invocation of procedure: SPI_finish() frees memory allocated for a plan. 
-   See SPI_saveplan().
-
-   If successful, NOT NULL pointer will be returned. Otherwise, you'll get
-   a NULL plan.  In both cases SPI_result will be set like the value returned
-   by SPI_exec, except
-
-   SPI_ERROR_ARGUMENT if query is NULL or nargs < 0 or nargs > 0 && argtypes
-   is NULL.
-
-
-void *SPI_saveplan(void *plan)
-
-   Currently, there is no ability to store prepared plans in the system
-   catalog and fetch them from there for execution. This will be implemented
-   in future versions.
-
-   As a work arround, there is the ability to reuse prepared plans in the
-   consequent invocations of your procedure in the current session.
-
-   SPI_saveplan() saves a passed plan (prepared by SPI_prepare()) in memory
-   protected from freeing by SPI_finish() and by the transaction manager and
-   returns a pointer to the saved plan.  You may save the pointer returned in
-   a local variable.  Always check if this pointer is NULL or not either when
-   preparing a plan or using an already prepared plan in SPI_execp (see below).
-
-   NOTE! If one of objects (relation, function, ...) referenced by prepared
-   plan is dropped during your session (by your backend or another) then the
-   results of SPI_execp (for this plan) will be unpredictable.
-
-   If successful, NOT NULL is returned otherwise, SPI_result is set to
-
-   SPI_ERROR_ARGUMENT if plan is NULL.
-   SPI_ERROR_UNCONNECTED if procedure is un-connected.
-
-
-int SPI_execp(void *plan, Datum * values, char *Nulls, int tcount)
-
-   Executes a plan prepared by SPI_prepare() (or returned by SPI_saveplan()).
-   Should only be called from a connected procedure.
-
-   plan is pointer to an execution plan, values points to actual parameter
-   values, Nulls - to array describing what parameters get NULLs ('n' -
-   NULL, ' ' - NOT NULL), tcount - number of tuples for which plan is to be
-   executed.
-
-   If Nulls is NULL then SPI assumes that all values (if any) are NOT NULL.
-
-   Returns the same value as SPI_exec, except
-
-   SPI_ERROR_ARGUMENT if plan is NULL or tcount < 0.
-   SPI_ERROR_PARAM if Values is NULL and plan prepared with some parameters.
-
-   If successful, SPI_tuptable and SPI_processed are initialized as in
-   SPI_exec().
-
-
-All functions described below may be used by connected and unconnected
-procedures.
-
-
-HeapTuple SPI_copytuple(HeapTuple tuple)
-
-   Makes copy of tuple in upper Executor context (see Memory management).
-
-   If successful, NOT NULL returned.  NULL (i.e. - error) will be returned
-   only if NULL is passed in.
-
-
-HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, 
-                int *attnum, Datum * Values, char *Nulls)
-
-   Modifies tuple of relation rel as described by the rest of the arguments.
-
-   natts is the number of attribute numbers in attnum.
-   attnum is an array of numbers of the attributes which are to be changed.
-   Values are new values for the attributes specified.
-   Nulls describes which of the attributes specified are NULL (if Nulls is
-   NULL then no NULLs).
-
-   If successful, NOT NULL pointer to new tuple returned. New tuple is
-   allocated in upper Executor context (see Memory management). Passed tuple
-   is not changed.
-
-   Returns NULL if failed with cause in SPI_result:
-
-   SPI_ERROR_ARGUMENT if rel is NULL or tuple is NULL or natts le 0 or
-   attnum is NULL or Values is NULL.
-   SPI_ERROR_NOATTRIBUTE if there is invalid (le 0 or gt number of
-   attributes in tuple) attribute number in attnum.
-
-
-int SPI_fnumber(TupleDesc tupdesc, char *fname)
-
-   Returns the attribute number for the attribute with name in fname.
-   tupdesc is tuple description.
-
-   Attribute numbers are 1 based.
-
-   Returns SPI_ERROR_NOATTRIBUTE if the named attribute is not found.
-
-
-char *SPI_fname(TupleDesc tupdesc, int fnumber)
-
-   Returns (a copy of) the name of the attribute with number fnumber.
-
-   Returns NULL and (SPI_ERROR_NOATTRIBUTE in SPI_result) if fnumber is
-   greater than the number of attributes in tupdesc or fnumber le 0.
-
-
-char *SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
-
-   Returns an external (string) representation of the value of attribute
-   fnumber in tuple with descriptor tupdesc.  Allocates memory as required
-   by the value.
-
-   Returns NULL if
-
-   attribute is NULL (SPI_result is 0 - no error);
-   fnumber is invalid (SPI_result is SPI_ERROR_NOATTRIBUTE);
-   there is no output function (SPI_result is SPI_ERROR_NOOUTFUNC).
-
-
-Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, 
-                    bool *isnull)
-
-   Returns the value of attribute fnumber in the tuple with descriptor
-   tupdesc. This is a binary value in internal form. This is not a copy!
-
-   Returns NULL indicator in *isnull.
-
-   SPI_result is SPI_ERROR_NOATTRIBUTE if fnumber is invalid.
-
-
-char *SPI_gettype(TupleDesc tupdesc, int fnumber)
-
-   Returns (a copy of) the type name for attribute fnumber.
-
-   Returns NULL (and SPI_ERROR_NOATTRIBUTE in SPI_result) if fnumber
-   is invalid.
-
-
-Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
-
-   Returns type OID for attribute fnumber.
-
-   SPI_result is SPI_ERROR_NOATTRIBUTE if fnumber is invalid.
-
-
-char *SPI_getrelname(Relation rel)
-
-   Returns (a copy of) the name of relation rel.
-
-
-void *SPI_palloc (Size size)
-
-   Allocates memory in upper Executor context (see Memory management).
-
-
-void *SPI_repalloc(void *pointer, Size size)
-
-   Re-allocates memory allocated in upper Executor context (see Memory
-   management).
-
-
-void SPI_pfree(void *pointer)
-
-   Frees memory allocated in upper Executor context (see Memory management).
-
-
-                         Memory management
-
-   Server allocates memory in memory contexts in such way that allocations
-made in one context may be freed by context destruction without affecting
-allocations made in other contexts. All allocations (via palloc(), etc) are
-made in the context which are chosen as current one. You'll get
-unpredictable results if you'll try to free (or reallocate) memory allocated
-not in current context.
-
-   Creation and switching between memory contexts are subject of SPI manager
-memory management.
-
-   SPI procedures deal with two memory contexts: upper Executor memory
-context and procedure memory context (if connected). 
-
-   Before a procedure is connected to the SPI manager, current memory context
-is upper Executor context so all allocation made by the procedure itself via
-palloc()/repalloc() or by SPI utility functions before connecting to SPI are
-made in this context.
-
-   After SPI_connect() is called current context is the procedure's one.  All
-allocations made via palloc()/repalloc() or by SPI utility functions (except
-for SPI_copytuple(), SPI_modifytuple, SPI_palloc() and SPI_repalloc()) are
-made in this context.
-
-   When a procedure disconnects from the SPI manager (via SPI_finish()) the
-current context is restored to the upper Executor context and all allocations
-made in the procedure memory context are freed and can't be used any more!
-
-   If you want to return something to the upper Executor then you have to
-allocate memory for this in the upper context!
-
-   SPI has no ability to automatically free allocations in the upper Executor
-context!
-
-   SPI automatically frees memory allocated during execution of a query when
-this query is done!
-
-
-
-                         Data changes visibility
-
-   PostgreSQL data changes visibility rule: during a query execution, data
-changes made by the query itself (via SQL-function, SPI-function, triggers)
-are invisible to the query scan.  For example, in query
-
-   INSERT INTO a SELECT * FROM a
-
-   tuples inserted are invisible for SELECT' scan.  In effect, this
-duplicates the database table within itself (subject to unique index
-rules, of course) without recursing.
-
-   Changes made by query Q are visible by queries which are started after
-query Q, no matter whether they are started inside Q (during the execution
-of Q) or after Q is done.
-
-   The last example of the usage of SPI procedure below demonstrates the
-visibility rule.
-
-
-                         Examples
-
-   There are more complex examples in in src/test/regress/regress.c and
-in contrib/spi.
-
-   This is a very simple example of SPI usage. The procedure execq accepts
-an SQL-query in its first argument and tcount in its second, executes the
-query using SPI_exec and returns the number of tuples for which the query
-executed:
-
-----------------------------------------------------------------------------
-#include "executor/spi.h"      /* this is what you need to work with SPI */
-
-int execq(text *sql, int cnt);
-
-int
-execq(text *sql, int cnt)
-{
-       int ret;
-       int proc = 0;
-       
-       SPI_connect();
-       
-       ret = SPI_exec(textout(sql), cnt);
-       
-       proc = SPI_processed;
-       /*
-        * If this is SELECT and some tuple(s) fetched -
-        * returns tuples to the caller via elog (NOTICE).
-        */
-       if ( ret == SPI_OK_SELECT && SPI_processed > 0 )
-       {
-               TupleDesc tupdesc = SPI_tuptable->tupdesc;
-               SPITupleTable *tuptable = SPI_tuptable;
-               char buf[8192];
-               int i;
-               
-               for (ret = 0; ret < proc; ret++)
-               {
-                       HeapTuple tuple = tuptable->vals[ret];
-                       
-                       for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
-                               sprintf(buf + strlen (buf), " %s%s",
-                                       SPI_getvalue(tuple, tupdesc, i),
-                                       (i == tupdesc->natts) ? " " : " |");
-                       elog (NOTICE, "EXECQ: %s", buf);
-               }
-       }
-
-       SPI_finish();
-
-       return (proc);
-}
-----------------------------------------------------------------------------
-
-   Now, compile and create the function:
-create function execq (text, int4) returns int4 as '...path_to_so' language 'c';
-
-vac=> select execq('create table a (x int4)', 0);
-execq
------
-    0
-(1 row)
-
-vac=> insert into a values (execq('insert into a values (0)',0));
-INSERT 167631 1
-vac=> select execq('select * from a',0);
-NOTICE:EXECQ:  0 <<< inserted by execq
-
-NOTICE:EXECQ:  1 <<< value returned by execq and inserted by upper INSERT
-
-execq
------
-    2
-(1 row)
-
-vac=> select execq('insert into a select x + 2 from a',1);
-execq
------
-    1
-(1 row)
-
-vac=> select execq('select * from a', 10);
-NOTICE:EXECQ:  0 
-
-NOTICE:EXECQ:  1 
-
-NOTICE:EXECQ:  2 <<< 0 + 2, only one tuple inserted - as specified
-
-execq
------
-    3            <<< 10 is max value only, 3 is real # of tuples
-(1 row)
-
-vac=> delete from a;
-DELETE 3
-vac=> insert into a values (execq('select * from a', 0) + 1);
-INSERT 167712 1
-vac=> select * from a;
-x
--
-1                <<< no tuples in a (0) + 1
-(1 row)
-
-vac=> insert into a values (execq('select * from a', 0) + 1);
-NOTICE:EXECQ:  0 
-INSERT 167713 1
-vac=> select * from a;
-x
--
-1
-2                <<< there was single tuple in a + 1
-(2 rows)
-
---   This demonstrates data changes visibility rule:
-
-vac=> insert into a select execq('select * from a', 0) * x from a;
-NOTICE:EXECQ:  1 
-NOTICE:EXECQ:  2 
-NOTICE:EXECQ:  1 
-NOTICE:EXECQ:  2 
-NOTICE:EXECQ:  2 
-INSERT 0 2
-vac=> select * from a;
-x
--
-1
-2
-2                <<< 2 tuples * 1 (x in first tuple)
-6                <<< 3 tuples (2 + 1 just inserted) * 2 (x in second tuple)
-(4 rows)             ^^^^^^^^ 
-                     tuples visible to execq() in different invocations
-
diff --git a/doc/trigger.txt b/doc/trigger.txt
deleted file mode 100644 (file)
index a3d95b1..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-
-               PostgreSQL Trigger Programming Guide
-
-   While the current version of PostgreSQL has various client interfaces
-such as Perl, Tcl, Python and C, it lacks an actual Procedural Language
-(PL).  We hope to have a proper PL one day.  In the meantime it is possible
-to call C functions as trigger actions.  Note that STATEMENT-level trigger
-events are not supported in the current version.  You can currently specify
-BEFORE or AFTER on INSERT, DELETE or UPDATE of a tuple as a trigger event.
-
-   If a trigger event occurs, the trigger manager (called by the Executor)
-initializes the global structure TriggerData *CurrentTriggerData (described
-below) and calls the trigger function to handle the event.
-
-   The trigger function must be created before the trigger is created as a
-function taking no arguments and returns opaque.
-
-   The syntax for creating triggers is as follows.
-
-   CREATE TRIGGER <trigger name> <BEFORE|AFTER> <INSERT|DELETE|UPDATE>
-       ON <relation name> FOR EACH <ROW|STATEMENT>
-       EXECUTE PROCEDURE <procedure name> (<function args>);
-
-   The name of the trigger is used if you ever have to delete the trigger.
-It is used as an argument to the DROP TRIGGER command.
-
-   The next word determines whether the function is called before or after
-the event.
-
-   The next element of the command determines on what event(s) will trigger
-the function.  Multiple events can be specified separated by OR.
-
-   The relation name determines which table the event applies to.
-
-   The FOR EACH statement determines whether the trigger is fired for each
-affected row or before (or after) the entire statement has completed.
-
-   The procedure name is the C function called.
-
-   The args are passed to the function in the CurrentTriggerData structure.
-The purpose of passing arguments to the function is to allow different
-triggers with similar requirements to call the same function.
-
-   Also, function may be used for triggering different relations (these
-functions are named as "general trigger functions").
-
-   As example of using both features above, there could be a general
-function that takes as its arguments two field names and puts the current
-user in one and the current timestamp in the other. This allows triggers to
-be written on INSERT events to automatically track creation of records in a
-transaction table for example. It could also be used as a "last updated"
-function if used in an UPDATE event.
-
-   Trigger functions return HeapTuple to the calling Executor.  This
-is ignored for triggers fired after an INSERT, DELETE or UPDATE operation
-but it allows BEFORE triggers to:
-
-   - return NULL to skip the operation for the current tuple (and so the
-     tuple will not be inserted/updated/deleted);
-   - return a pointer to another tuple (INSERT and UPDATE only) which will
-     be inserted (as the new version of the updated tuple if UPDATE) instead
-     of original tuple.
-
-   Note, that there is no initialization performed by the CREATE TRIGGER
-handler.  This will be changed in the future.  Also, if more than one trigger
-is defined for the same event on the same relation, the order of trigger
-firing is unpredictable. This may be changed in the future.
-
-   If a trigger function executes SQL-queries (using SPI) then these queries
-may fire triggers again. This is known as cascading triggers.  There is no
-explicit limitation on the number of cascade levels.
-
-   If a trigger is fired by INSERT and inserts a new tuple in the same
-relation then this trigger will be fired again.  Currently, there is nothing
-provided for synchronization (etc) of these cases but this may change.  At
-the moment, there is function funny_dup17() in the regress tests which uses
-some techniques to stop recursion (cascading) on itself...
-
-
-                 Interaction with the trigger manager
-
-   As mentioned above, when function is called by the trigger manager,
-structure TriggerData *CurrentTriggerData is NOT NULL and initialized.  So
-it is better to check CurrentTriggerData against being NULL at the start
-and set it to NULL just after fetching the information to prevent calls to
-a trigger function not from the trigger manager.
-
-   struct TriggerData is defined in src/include/commands/trigger.h:
-
-typedef struct TriggerData
-{
-       TriggerEvent    tg_event;
-       Relation        tg_relation;
-       HeapTuple       tg_trigtuple;
-       HeapTuple       tg_newtuple;
-       Trigger         *tg_trigger;
-} TriggerData;
-
-tg_event 
-   describes event for which the function is called. You may use the
-   following macros to examine tg_event:
-
-   TRIGGER_FIRED_BEFORE(event) returns TRUE if trigger fired BEFORE;
-   TRIGGER_FIRED_AFTER(event) returns TRUE if trigger fired AFTER;
-   TRIGGER_FIRED_FOR_ROW(event) returns TRUE if trigger fired for
-                                ROW-level event;
-   TRIGGER_FIRED_FOR_STATEMENT(event) returns TRUE if trigger fired for
-                                STATEMENT-level event;
-   TRIGGER_FIRED_BY_INSERT(event) returns TRUE if trigger fired by INSERT;
-   TRIGGER_FIRED_BY_DELETE(event) returns TRUE if trigger fired by DELETE;
-   TRIGGER_FIRED_BY_UPDATE(event) returns TRUE if trigger fired by UPDATE.
-
-tg_relation
-   is pointer to structure describing the triggered relation. Look at
-   src/include/utils/rel.h for details about this structure.  The most
-   interest things are tg_relation->rd_att (descriptor of the relation
-   tuples) and tg_relation->rd_rel->relname (relation's name. This is not
-   char*, but NameData.  Use SPI_getrelname(tg_relation) to get char* if
-   you need a copy of name).
-
-tg_trigtuple
-   is a pointer to the tuple for which the trigger is fired. This is the tuple
-   being inserted (if INSERT), deleted (if DELETE) or updated (if UPDATE).
-   If INSERT/DELETE then this is what you are to return to Executor if 
-   you don't want to replace tuple with another one (INSERT) or skip the
-   operation.
-
-tg_newtuple
-   is a pointer to the new version of tuple if UPDATE and NULL if this is
-   for an INSERT or a DELETE. This is what you are to return to Executor if
-   UPDATE and you don't want to replace this tuple with another one or skip
-   the operation.
-
-tg_trigger
-   is pointer to structure Trigger defined in src/include/utils/rel.h:
-
-typedef struct Trigger
-{
-       char            *tgname;
-       Oid             tgfoid;
-       func_ptr        tgfunc;
-       int16           tgtype;
-       int16           tgnargs;
-       int16           tgattr[8];
-       char            **tgargs;
-} Trigger;
-
-   tgname is the trigger's name, tgnargs is number of arguments in tgargs,
-   tgargs is an array of pointers to the arguments specified in the CREATE
-   TRIGGER statement. Other members are for internal use only.
-
-
-                         Visibility of Data Changes
-
-   PostgreSQL data changes visibility rule: during a query execution, data
-changes made by the query itself (via SQL-function, SPI-function, triggers)
-are invisible to the query scan.  For example, in query
-
-   INSERT INTO a SELECT * FROM a
-
-   tuples inserted are invisible for SELECT' scan.  In effect, this
-duplicates the database table within itself (subject to unique index
-rules, of course) without recursing.
-
-   But keep in mind this notice about visibility in the SPI documentation:
-
-   Changes made by query Q are visible by queries which are started after
-   query Q, no matter whether they are started inside Q (during the
-   execution of Q) or after Q is done.
-
-   This is true for triggers as well so, though a tuple being inserted
-(tg_trigtuple) is not visible to queries in a BEFORE trigger, this tuple
-(just inserted) is visible to queries in an AFTER trigger, and to queries
-in BEFORE/AFTER triggers fired after this!
-
-
-                         Examples
-
-   There are more complex examples in in src/test/regress/regress.c and
-in contrib/spi.
-
-   Here is a very simple example of trigger usage.  Function trigf reports
-the number of tuples in the triggered relation ttest and skips the
-operation if the query attempts to insert NULL into x (i.e - it acts as a
-NOT NULL constraint but doesn't abort the transaction).
-
-----------------------------------------------------------------------------
-#include "executor/spi.h"      /* this is what you need to work with SPI */
-#include "commands/trigger.h"  /* -"- and triggers */
-
-HeapTuple              trigf(void);
-
-HeapTuple
-trigf()
-{
-       TupleDesc       tupdesc;
-       HeapTuple       rettuple;
-       char            *when;
-       bool            checknull = false;
-       bool            isnull;
-       int             ret, i;
-
-       if (!CurrentTriggerData)
-               elog(WARN, "trigf: triggers are not initialized");
-       
-       /* tuple to return to Executor */
-       if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
-               rettuple = CurrentTriggerData->tg_newtuple;
-       else
-               rettuple = CurrentTriggerData->tg_trigtuple;
-       
-       /* check for NULLs ? */
-       if (!TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event) &&
-               TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
-               checknull = true;
-       
-       if (TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
-               when = "before";
-       else
-               when = "after ";
-       
-       tupdesc = CurrentTriggerData->tg_relation->rd_att;
-       CurrentTriggerData = NULL;
-       
-       /* Connect to SPI manager */
-       if ((ret = SPI_connect()) < 0)
-               elog(WARN, "trigf (fired %s): SPI_connect returned %d", when, ret);
-       
-       /* Get number of tuples in relation */
-       ret = SPI_exec("select count(*) from ttest", 0);
-       
-       if (ret < 0)
-               elog(WARN, "trigf (fired %s): SPI_exec returned %d", when, ret);
-       
-       i = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull);
-       
-       elog (NOTICE, "trigf (fired %s): there are %d tuples in ttest", when, i);
-       
-       SPI_finish();
-       
-       if (checknull)
-       {
-               i = SPI_getbinval(rettuple, tupdesc, 1, &isnull);
-               if (isnull)
-                       rettuple = NULL;
-       }
-
-       return (rettuple);
-}
-----------------------------------------------------------------------------
-
-   Now, compile and 
-create table ttest (x int4);
-create function trigf () returns opaque as 
-'...path_to_so' language 'c';
-
-vac=> create trigger tbefore before insert or update or delete on ttest 
-for each row execute procedure trigf();
-CREATE
-vac=> create trigger tafter after insert or update or delete on ttest 
-for each row execute procedure trigf();
-CREATE
-vac=> insert into ttest values (null);
-NOTICE:trigf (fired before): there are 0 tuples in ttest
-INSERT 0 0
-
--- Insertion skipped and AFTER trigger is not fired
-
-vac=> select * from ttest;
-x
--
-(0 rows)
-
-vac=> insert into ttest values (1);
-NOTICE:trigf (fired before): there are 0 tuples in ttest
-NOTICE:trigf (fired after ): there are 1 tuples in ttest
-                                       ^^^^^^^^
-                             remember what we said about visibility.
-INSERT 167793 1
-vac=> select * from ttest;
-x
--
-1
-(1 row)
-
-vac=> insert into ttest select x * 2 from ttest;
-NOTICE:trigf (fired before): there are 1 tuples in ttest
-NOTICE:trigf (fired after ): there are 2 tuples in ttest
-                                       ^^^^^^^^
-                             remember what we said about visibility.
-INSERT 167794 1
-vac=> select * from ttest;
-x
--
-1
-2
-(2 rows)
-
-vac=> update ttest set x = null where x = 2;
-NOTICE:trigf (fired before): there are 2 tuples in ttest
-UPDATE 0
-vac=> update ttest set x = 4 where x = 2;
-NOTICE:trigf (fired before): there are 2 tuples in ttest
-NOTICE:trigf (fired after ): there are 2 tuples in ttest
-UPDATE 1
-vac=> select * from ttest;
-x
--
-1
-4
-(2 rows)
-
-vac=> delete from ttest;
-NOTICE:trigf (fired before): there are 2 tuples in ttest
-NOTICE:trigf (fired after ): there are 1 tuples in ttest
-NOTICE:trigf (fired before): there are 1 tuples in ttest
-NOTICE:trigf (fired after ): there are 0 tuples in ttest
-                                       ^^^^^^^^
-                             remember what we said about visibility.
-DELETE 2
-vac=> select * from ttest;
-x
--
-(0 rows)
-