trigger.sgml
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:12k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. <Chapter Id="triggers">
  2. <Title>Triggers</Title>
  3. <Para>
  4. <ProductName>Postgres</ProductName> has various client interfaces
  5. such as Perl, Tcl, Python and C, as well as two
  6. <FirstTerm>Procedural Languages</FirstTerm>
  7. (PL).  It is also possible
  8. to call C functions as trigger actions.  Note that STATEMENT-level trigger
  9. events are not supported in the current version.  You can currently specify
  10. BEFORE or AFTER on INSERT, DELETE or UPDATE of a tuple as a trigger event.
  11. </Para>
  12. <Sect1>
  13. <Title>Trigger Creation</Title>
  14. <Para>
  15.    If a trigger event occurs, the trigger manager (called by the Executor)
  16. initializes the global structure TriggerData *CurrentTriggerData (described
  17. below) and calls the trigger function to handle the event.
  18. </Para>
  19. <Para>
  20.    The trigger function must be created before the trigger is created as a
  21. function taking no arguments and returns opaque.
  22. </Para>
  23. <Para>
  24.    The syntax for creating triggers is as follows:
  25. <ProgramListing>
  26.    CREATE TRIGGER &lt;trigger name&gt; &lt;BEFORE|AFTER&gt; &lt;INSERT|DELETE|UPDATE&gt;
  27.        ON &lt;relation name&gt; FOR EACH &lt;ROW|STATEMENT&gt;
  28.        EXECUTE PROCEDURE &lt;procedure name&gt; (&lt;function args&gt;);
  29. </ProgramListing>
  30. </Para>
  31. <Para>
  32.    The name of the trigger is used if you ever have to delete the trigger.
  33. It is used as an argument to the DROP TRIGGER command.
  34. </Para>
  35. <Para>
  36.    The next word determines whether the function is called before or after
  37. the event.
  38. </Para>
  39. <Para>
  40.    The next element of the command determines on what event(s) will trigger
  41. the function.  Multiple events can be specified separated by OR.
  42. </Para>
  43. <Para>
  44.    The relation name determines which table the event applies to.
  45. </Para>
  46. <Para>
  47.    The FOR EACH statement determines whether the trigger is fired for each
  48. affected row or before (or after) the entire statement has completed.
  49. </Para>
  50. <Para>
  51.    The procedure name is the C function called.
  52. </Para>
  53. <Para>
  54.    The args are passed to the function in the CurrentTriggerData structure.
  55. The purpose of passing arguments to the function is to allow different
  56. triggers with similar requirements to call the same function.
  57. </Para>
  58. <Para>
  59.    Also, function may be used for triggering different relations (these
  60. functions are named as "general trigger functions").
  61. </Para>
  62. <Para>
  63.    As example of using both features above, there could be a general
  64. function that takes as its arguments two field names and puts the current
  65. user in one and the current timestamp in the other. This allows triggers to
  66. be written on INSERT events to automatically track creation of records in a
  67. transaction table for example. It could also be used as a "last updated"
  68. function if used in an UPDATE event.
  69. </Para>
  70. <Para>
  71.    Trigger functions return HeapTuple to the calling Executor.  This
  72. is ignored for triggers fired after an INSERT, DELETE or UPDATE operation
  73. but it allows BEFORE triggers to:
  74.    - return NULL to skip the operation for the current tuple (and so the
  75.      tuple will not be inserted/updated/deleted);
  76.    - return a pointer to another tuple (INSERT and UPDATE only) which will
  77.      be inserted (as the new version of the updated tuple if UPDATE) instead
  78.      of original tuple.
  79. </Para>
  80. <Para>
  81.    Note, that there is no initialization performed by the CREATE TRIGGER
  82. handler.  This will be changed in the future.  Also, if more than one trigger
  83. is defined for the same event on the same relation, the order of trigger
  84. firing is unpredictable. This may be changed in the future.
  85. </Para>
  86. <Para>
  87.    If a trigger function executes SQL-queries (using SPI) then these queries
  88. may fire triggers again. This is known as cascading triggers.  There is no
  89. explicit limitation on the number of cascade levels.
  90. </Para>
  91. <Para>
  92.    If a trigger is fired by INSERT and inserts a new tuple in the same
  93. relation then this trigger will be fired again.  Currently, there is nothing
  94. provided for synchronization (etc) of these cases but this may change.  At
  95. the moment, there is function funny_dup17() in the regress tests which uses
  96. some techniques to stop recursion (cascading) on itself...
  97. </Para>
  98. </Sect1>
  99. <Sect1>
  100. <Title>Interaction with the Trigger Manager</Title>
  101. <Para>
  102.    As mentioned above, when function is called by the trigger manager,
  103. structure TriggerData *CurrentTriggerData is NOT NULL and initialized.  So
  104. it is better to check CurrentTriggerData against being NULL at the start
  105. and set it to NULL just after fetching the information to prevent calls to
  106. a trigger function not from the trigger manager.
  107. </Para>
  108. <Para>
  109.    struct TriggerData is defined in src/include/commands/trigger.h:
  110. <ProgramListing>
  111. typedef struct TriggerData
  112. {
  113. TriggerEvent tg_event;
  114. Relation tg_relation;
  115. HeapTuple tg_trigtuple;
  116. HeapTuple tg_newtuple;
  117. Trigger *tg_trigger;
  118. } TriggerData;
  119. </ProgramListing>
  120. <ProgramListing>
  121. tg_event 
  122.    describes event for which the function is called. You may use the
  123.    following macros to examine tg_event:
  124.    TRIGGER_FIRED_BEFORE(event) returns TRUE if trigger fired BEFORE;
  125.    TRIGGER_FIRED_AFTER(event) returns TRUE if trigger fired AFTER;
  126.    TRIGGER_FIRED_FOR_ROW(event) returns TRUE if trigger fired for
  127.                                 ROW-level event;
  128.    TRIGGER_FIRED_FOR_STATEMENT(event) returns TRUE if trigger fired for
  129.                                 STATEMENT-level event;
  130.    TRIGGER_FIRED_BY_INSERT(event) returns TRUE if trigger fired by INSERT;
  131.    TRIGGER_FIRED_BY_DELETE(event) returns TRUE if trigger fired by DELETE;
  132.    TRIGGER_FIRED_BY_UPDATE(event) returns TRUE if trigger fired by UPDATE.
  133. tg_relation
  134.    is pointer to structure describing the triggered relation. Look at
  135.    src/include/utils/rel.h for details about this structure.  The most
  136.    interest things are tg_relation->rd_att (descriptor of the relation
  137.    tuples) and tg_relation->rd_rel->relname (relation's name. This is not
  138.    char*, but NameData.  Use SPI_getrelname(tg_relation) to get char* if
  139.    you need a copy of name).
  140. tg_trigtuple
  141.    is a pointer to the tuple for which the trigger is fired. This is the tuple
  142.    being inserted (if INSERT), deleted (if DELETE) or updated (if UPDATE).
  143.    If INSERT/DELETE then this is what you are to return to Executor if 
  144.    you don't want to replace tuple with another one (INSERT) or skip the
  145.    operation.
  146. tg_newtuple
  147.    is a pointer to the new version of tuple if UPDATE and NULL if this is
  148.    for an INSERT or a DELETE. This is what you are to return to Executor if
  149.    UPDATE and you don't want to replace this tuple with another one or skip
  150.    the operation.
  151. tg_trigger
  152.    is pointer to structure Trigger defined in src/include/utils/rel.h:
  153. typedef struct Trigger
  154. {
  155. char *tgname;
  156. Oid tgfoid;
  157. func_ptr tgfunc;
  158. int16 tgtype;
  159. int16 tgnargs;
  160. int16 tgattr[8];
  161. char **tgargs;
  162. } Trigger;
  163.    tgname is the trigger's name, tgnargs is number of arguments in tgargs,
  164.    tgargs is an array of pointers to the arguments specified in the CREATE
  165.    TRIGGER statement. Other members are for internal use only.
  166. </ProgramListing>
  167. </Para>
  168. </Sect1>
  169. <Sect1>
  170. <Title>Visibility of Data Changes</Title>
  171. <Para>
  172.    <ProductName>Postgres</ProductName> data changes visibility rule: during a query execution, data
  173. changes made by the query itself (via SQL-function, SPI-function, triggers)
  174. are invisible to the query scan.  For example, in query
  175. <ProgramListing>
  176.    INSERT INTO a SELECT * FROM a
  177. </ProgramListing>
  178.    tuples inserted are invisible for SELECT' scan.  In effect, this
  179. duplicates the database table within itself (subject to unique index
  180. rules, of course) without recursing.
  181. </Para>
  182. <Para>
  183.    But keep in mind this notice about visibility in the SPI documentation:
  184. <ProgramListing>
  185.    Changes made by query Q are visible by queries which are started after
  186.    query Q, no matter whether they are started inside Q (during the
  187.    execution of Q) or after Q is done.
  188. </ProgramListing>
  189. </Para>
  190. <Para>
  191.    This is true for triggers as well so, though a tuple being inserted
  192. (tg_trigtuple) is not visible to queries in a BEFORE trigger, this tuple
  193. (just inserted) is visible to queries in an AFTER trigger, and to queries
  194. in BEFORE/AFTER triggers fired after this!
  195. </Para>
  196. </Sect1>
  197. <Sect1>
  198. <Title>Examples</Title>
  199. <Para>
  200.    There are more complex examples in in src/test/regress/regress.c and
  201. in contrib/spi.
  202. </Para>
  203. <Para>
  204.    Here is a very simple example of trigger usage.  Function trigf reports
  205. the number of tuples in the triggered relation ttest and skips the
  206. operation if the query attempts to insert NULL into x (i.e - it acts as a
  207. NOT NULL constraint but doesn't abort the transaction).
  208. <ProgramListing>
  209. #include "executor/spi.h" /* this is what you need to work with SPI */
  210. #include "commands/trigger.h" /* -"- and triggers */
  211. HeapTuple trigf(void);
  212. HeapTuple
  213. trigf()
  214. {
  215. TupleDesc tupdesc;
  216. HeapTuple rettuple;
  217. char *when;
  218. bool checknull = false;
  219. bool isnull;
  220. int ret, i;
  221. if (!CurrentTriggerData)
  222. elog(WARN, "trigf: triggers are not initialized");
  223. /* tuple to return to Executor */
  224. if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
  225. rettuple = CurrentTriggerData->tg_newtuple;
  226. else
  227. rettuple = CurrentTriggerData->tg_trigtuple;
  228. /* check for NULLs ? */
  229. if (!TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event) &&
  230. TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
  231. checknull = true;
  232. if (TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
  233. when = "before";
  234. else
  235. when = "after ";
  236. tupdesc = CurrentTriggerData->tg_relation->rd_att;
  237. CurrentTriggerData = NULL;
  238. /* Connect to SPI manager */
  239. if ((ret = SPI_connect()) < 0)
  240. elog(WARN, "trigf (fired %s): SPI_connect returned %d", when, ret);
  241. /* Get number of tuples in relation */
  242. ret = SPI_exec("select count(*) from ttest", 0);
  243. if (ret < 0)
  244. elog(WARN, "trigf (fired %s): SPI_exec returned %d", when, ret);
  245. i = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &amp;isnull);
  246. elog (NOTICE, "trigf (fired %s): there are %d tuples in ttest", when, i);
  247. SPI_finish();
  248. if (checknull)
  249. {
  250. i = SPI_getbinval(rettuple, tupdesc, 1, &amp;isnull);
  251. if (isnull)
  252. rettuple = NULL;
  253. }
  254. return (rettuple);
  255. }
  256. </ProgramListing>
  257. </Para>
  258. <Para>
  259.    Now, compile and 
  260. create table ttest (x int4);
  261. create function trigf () returns opaque as 
  262. '...path_to_so' language 'c';
  263. <ProgramListing>
  264. vac=> create trigger tbefore before insert or update or delete on ttest 
  265. for each row execute procedure trigf();
  266. CREATE
  267. vac=> create trigger tafter after insert or update or delete on ttest 
  268. for each row execute procedure trigf();
  269. CREATE
  270. vac=> insert into ttest values (null);
  271. NOTICE:trigf (fired before): there are 0 tuples in ttest
  272. INSERT 0 0
  273. -- Insertion skipped and AFTER trigger is not fired
  274. vac=> select * from ttest;
  275. x
  276. -
  277. (0 rows)
  278. vac=> insert into ttest values (1);
  279. NOTICE:trigf (fired before): there are 0 tuples in ttest
  280. NOTICE:trigf (fired after ): there are 1 tuples in ttest
  281.                                        ^^^^^^^^
  282.                              remember what we said about visibility.
  283. INSERT 167793 1
  284. vac=> select * from ttest;
  285. x
  286. -
  287. 1
  288. (1 row)
  289. vac=> insert into ttest select x * 2 from ttest;
  290. NOTICE:trigf (fired before): there are 1 tuples in ttest
  291. NOTICE:trigf (fired after ): there are 2 tuples in ttest
  292.                                        ^^^^^^^^
  293.                              remember what we said about visibility.
  294. INSERT 167794 1
  295. vac=> select * from ttest;
  296. x
  297. -
  298. 1
  299. 2
  300. (2 rows)
  301. vac=> update ttest set x = null where x = 2;
  302. NOTICE:trigf (fired before): there are 2 tuples in ttest
  303. UPDATE 0
  304. vac=> update ttest set x = 4 where x = 2;
  305. NOTICE:trigf (fired before): there are 2 tuples in ttest
  306. NOTICE:trigf (fired after ): there are 2 tuples in ttest
  307. UPDATE 1
  308. vac=> select * from ttest;
  309. x
  310. -
  311. 1
  312. 4
  313. (2 rows)
  314. vac=> delete from ttest;
  315. NOTICE:trigf (fired before): there are 2 tuples in ttest
  316. NOTICE:trigf (fired after ): there are 1 tuples in ttest
  317. NOTICE:trigf (fired before): there are 1 tuples in ttest
  318. NOTICE:trigf (fired after ): there are 0 tuples in ttest
  319.                                        ^^^^^^^^
  320.                              remember what we said about visibility.
  321. DELETE 2
  322. vac=> select * from ttest;
  323. x
  324. -
  325. (0 rows)
  326. </ProgramListing>
  327. </Para>
  328. </Sect1>
  329. </Chapter>