Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/hsqldb/TriggerDef.java


1   /* Copyright (c) 2001-2002, The HSQL Development Group
2    * All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    *
7    * Redistributions of source code must retain the above copyright notice, this
8    * list of conditions and the following disclaimer.
9    *
10   * Redistributions in binary form must reproduce the above copyright notice,
11   * this list of conditions and the following disclaimer in the documentation
12   * and/or other materials provided with the distribution.
13   *
14   * Neither the name of the HSQL Development Group nor the names of its
15   * contributors may be used to endorse or promote products derived from this
16   * software without specific prior written permission.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21   * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, 
22   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  
31  
32  package org.hsqldb;
33  
34  // peterhudson@users 20020130 - patch 478657 by peterhudson - triggers support
35  // fredt@users 20020130 - patch 1.7.0 by fredt
36  // added new class as jdk 1.1 does not allow use of LinkedList
37  import org.hsqldb.lib.HsqlDeque;
38  
39  /**
40   *  TriggerDef class declaration Definition and execution of triggers
41   *  Development of the trigger implementation sponsored by Logicscope
42   *  Realisations Ltd
43   *
44   * @author  Logicscope Realisations Ltd
45   * @version  1.7.0 (1.0.0.3) Revision History: 1.0.0.1 First release in hsqldb 1.61
46   *      1.0.0.2 'nowait' support to prevent deadlock 1.0.0.3 multiple row
47   *      queue for each trigger
48   */
49  class TriggerDef extends Thread {
50  
51      /**
52       *  member variables
53       */
54      static final int NUM_TRIGGER_OPS = 3;    // ie ins,del,upd
55      static final int NUM_TRIGS       = NUM_TRIGGER_OPS * 2 * 2;
56  
57      // indexes into the triggers list
58      static final int INSERT_AFTER      = 0;
59      static final int DELETE_AFTER      = 1;
60      static final int UPDATE_AFTER      = 2;
61      static final int INSERT_BEFORE     = INSERT_AFTER + NUM_TRIGGER_OPS;
62      static final int DELETE_BEFORE     = DELETE_AFTER + NUM_TRIGGER_OPS;
63      static final int UPDATE_BEFORE     = UPDATE_AFTER + NUM_TRIGGER_OPS;
64      static final int INSERT_AFTER_ROW  = INSERT_AFTER + 2 * NUM_TRIGGER_OPS;
65      static final int DELETE_AFTER_ROW  = DELETE_AFTER + 2 * NUM_TRIGGER_OPS;
66      static final int UPDATE_AFTER_ROW  = UPDATE_AFTER + 2 * NUM_TRIGGER_OPS;
67      static final int INSERT_BEFORE_ROW = INSERT_BEFORE + 2 * NUM_TRIGGER_OPS;
68      static final int DELETE_BEFORE_ROW = DELETE_BEFORE + 2 * NUM_TRIGGER_OPS;
69      static final int UPDATE_BEFORE_ROW = UPDATE_BEFORE + 2 * NUM_TRIGGER_OPS;
70  
71      // other variables
72      String  name;
73      String  when;
74      String  operation;
75      boolean forEachRow;
76      boolean nowait;                          // block or overwrite if queue full
77      int     maxRowsQueued;                   // max size of queue of pending triggers
78  
79      public static int getDefaultQueueSize() {
80          return defaultQueueSize;
81      }
82  
83      protected static int defaultQueueSize = 1024;
84      Table                table;
85      Trigger              trig;
86      String               fire;
87      int                  vectorIndx;     // index into Vector[]
88  
89      //protected boolean busy;               // firing trigger in progress
90      protected HsqlDeque pendingQueue;    // row triggers pending
91      protected int       rowsQueued;      // rows in pendingQueue
92      protected boolean   valid;           // parsing valid
93  
94      /**
95       *  Constructor declaration create an object from the components of an
96       *  SQL CREATE TRIGGER statement
97       *
98       * @param  sName
99       * @param  sWhen
100      * @param  sOper
101      * @param  bForEach
102      * @param  pTab
103      * @param  pTrig
104      * @param  sFire
105      * @param  bNowait Description of the Parameter
106      * @param  nQueueSize Description of the Parameter
107      */
108     public TriggerDef(String sName, String sWhen, String sOper,
109                       boolean bForEach, Table pTab, Trigger pTrig,
110                       String sFire, boolean bNowait, int nQueueSize) {
111 
112         name          = sName.toUpperCase();
113         when          = sWhen.toUpperCase();
114         operation     = sOper.toUpperCase();
115         forEachRow    = bForEach;
116         nowait        = bNowait;
117         maxRowsQueued = nQueueSize;
118         table         = pTab;
119         trig          = pTrig;
120         fire          = sFire;
121         vectorIndx    = SqlToIndex();
122 
123         //busy = false;
124         rowsQueued   = 0;
125         pendingQueue = new HsqlDeque();
126 
127         if (vectorIndx < 0) {
128             valid = false;
129         } else {
130             valid = true;
131         }
132     }
133 
134     /**
135      *  Method declaration
136      *
137      * @return
138      */
139     public StringBuffer toBuf() {
140 
141         StringBuffer a = new StringBuffer(256);
142 
143         a.append("CREATE TRIGGER ");
144         a.append(name);
145         a.append(" ");
146         a.append(when);
147         a.append(" ");
148         a.append(operation);
149         a.append(" ON ");
150         a.append(table.getName().statementName);
151 
152         if (forEachRow) {
153             a.append(" FOR EACH ROW ");
154         }
155 
156         if (nowait) {
157             a.append(" NOWAIT ");
158         }
159 
160         if (maxRowsQueued != getDefaultQueueSize()) {
161             a.append(" QUEUE ");
162             a.append(maxRowsQueued);    // no need for trailing space
163         }
164 
165         a.append(" CALL ");
166         a.append(fire);
167 
168         return a;
169     }
170 
171     /**
172      *  SqlToIndex method declaration <P>
173      *
174      *  Given the SQL creating the trigger, say what the index to the
175      *  Vector[] is
176      *
177      * @return  index to the Vector[]
178      */
179     public int SqlToIndex() {
180 
181         int indx;
182 
183         if (operation.equals("INSERT")) {
184             indx = INSERT_AFTER;
185         } else if (operation.equals("DELETE")) {
186             indx = DELETE_AFTER;
187         } else if (operation.equals("UPDATE")) {
188             indx = UPDATE_AFTER;
189         } else {
190             indx = -1;
191         }
192 
193         if (when.equals("BEFORE")) {
194             indx += NUM_TRIGGER_OPS;    // number of operations
195         } else if (!when.equals("AFTER")) {
196             indx = -1;
197         }
198 
199         if (forEachRow) {
200             indx += 2 * NUM_TRIGGER_OPS;
201         }
202 
203         return indx;
204     }
205 
206     /**
207      *  run method declaration <P>
208      *
209      *  the trigger JSP is run in its own thread here. Its job is simply to
210      *  wait until it is told by the main thread that it should fire the
211      *  trigger.
212      */
213     public void run() {
214 
215         boolean keepGoing = true;
216 
217         while (keepGoing) {
218             Object trigRow[] = pop();
219 
220             trig.fire(name, table.getName().name, trigRow);
221         }
222     }
223 
224     /**
225      *  pop method declaration <P>
226      *
227      *  The consumer (trigger) thread waits for an event to be queued <P>
228      *
229      *  <B>Note: </B> This push/pop pairing assumes a single producer thread
230      *  and a single consumer thread _only_.
231      *
232      * @return  Description of the Return Value
233      */
234     synchronized Object[] pop() {
235 
236         if (rowsQueued == 0) {
237             try {
238                 wait();    // this releases the lock monitor
239             } catch (InterruptedException e) {
240 
241                 /* ignore and resume */
242             }
243         }
244 
245         rowsQueued--;
246 
247         notify();    // notify push's wait
248 
249         return (Object[]) pendingQueue.removeFirst();
250     }
251 
252     /**
253      *  push method declaration <P>
254      *
255      *  The main thread tells the trigger thread to fire by this call
256      *
257      * @param  row Description of the Parameter
258      */
259     synchronized void push(Object row[]) {
260 
261         if (rowsQueued >= maxRowsQueued) {
262             if (nowait) {
263                 pendingQueue.removeLast();    // overwrite last
264             } else {
265                 try {
266                     wait();
267                 } catch (InterruptedException e) {
268 
269                     /* ignore and resume */
270                 }
271 
272                 rowsQueued++;
273             }
274         } else {
275             rowsQueued++;
276         }
277 
278         pendingQueue.add(row);
279         notify();    // notify pop's wait
280     }
281 
282     /**
283      *  Method declaration
284      *
285      * @return
286      */
287     public static int numTrigs() {
288         return NUM_TRIGS;
289     }
290 
291     /**
292      *  Method declaration
293      *
294      * @return
295      */
296     public boolean isBusy() {
297         return rowsQueued != 0;
298     }
299 
300     /**
301      *  Method declaration
302      *
303      * @return
304      */
305     public boolean isValid() {
306         return valid;
307     }
308 }