1 | /* |
2 | |
3 | Derby - Class org.apache.derby.iapi.sql.dictionary.TriggerDescriptor |
4 | |
5 | Copyright 1999, 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.iapi.sql.dictionary; |
22 | |
23 | import org.apache.derby.iapi.services.io.Formatable; |
24 | import org.apache.derby.iapi.sql.depend.Dependent; |
25 | import org.apache.derby.iapi.sql.depend.Provider; |
26 | import org.apache.derby.iapi.error.StandardException; |
27 | import org.apache.derby.catalog.ReferencedColumns; |
28 | import org.apache.derby.catalog.UUID; |
29 | import java.sql.Timestamp; |
30 | |
31 | import org.apache.derby.iapi.reference.SQLState; |
32 | import org.apache.derby.iapi.services.sanity.SanityManager; |
33 | import org.apache.derby.iapi.sql.StatementType; |
34 | import org.apache.derby.catalog.DependableFinder; |
35 | import org.apache.derby.catalog.Dependable; |
36 | import org.apache.derby.iapi.services.io.StoredFormatIds; |
37 | import org.apache.derby.iapi.error.StandardException; |
38 | import org.apache.derby.iapi.sql.depend.DependencyManager; |
39 | import org.apache.derby.iapi.sql.depend.Dependent; |
40 | import org.apache.derby.iapi.sql.depend.Dependency; |
41 | import org.apache.derby.iapi.sql.depend.Provider; |
42 | import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; |
43 | import org.apache.derby.iapi.services.context.ContextManager; |
44 | import org.apache.derby.iapi.services.context.ContextService; |
45 | import java.io.ObjectOutput; |
46 | import java.io.ObjectInput; |
47 | import java.io.IOException; |
48 | |
49 | /** |
50 | * A trigger. |
51 | * <p> |
52 | * We are dependent on TableDescriptors, SPSDescriptors (for our |
53 | * WHEN clause and our action). Note that we don't strictly |
54 | * need to be dependent on out SPSes because we could just disallow |
55 | * anyone from dropping an sps of type 'T', but to keep dependencies |
56 | * uniform, we'll do be dependent. |
57 | * <p> |
58 | * We are a provider for DML (PreparedStatements or SPSes) |
59 | * |
60 | * The public methods for this class are: |
61 | * |
62 | * <ol> |
63 | * <li>getUUID |
64 | * <li>getName |
65 | * <li>getSchemaDescriptor |
66 | * <li> public boolean listensForEvent(int event); |
67 | * <li> public int getTriggerEventMask(); |
68 | * <li> public Timestamp getCreationTimestamp(); |
69 | * <li> public boolean isBeforeTrigger(); |
70 | * <li> public boolean isRowTrigger(); |
71 | * <li> public UUID getActionId(); |
72 | * <li> public SPSDescriptor getActionSPS(); |
73 | * <li> public UUID getWhenClauseId(); |
74 | * <li> public SPSDescriptor getWhenClauseSPS() |
75 | * <li> public TableDescriptor getTableDescriptor() |
76 | * <li> public ReferencedColumns getReferencedColumnsDescriptor() |
77 | * <li> public int[] getReferencedCols(); |
78 | * <li> public boolean isEnabled(); |
79 | * <li> public void setEnabled(); |
80 | * <li> public void setDisabled(); |
81 | * <li> public boolean needsToFire(int stmtType, int[] modifiedCols) |
82 | * <li> public String getTriggerDefinition(); |
83 | * <li> public boolean getReferencingOld(); |
84 | * <li> public boolean getReferencingNew(); |
85 | * <li> public String getOldReferencingName(); |
86 | * <li> public String getNewReferencingName(); |
87 | * </ol> |
88 | * @author Jamie |
89 | */ |
90 | public class TriggerDescriptor extends TupleDescriptor |
91 | implements UniqueSQLObjectDescriptor, Provider, Dependent, Formatable |
92 | { |
93 | // field that we want users to be able to know about |
94 | public static final int SYSTRIGGERS_STATE_FIELD = 8; |
95 | |
96 | public static final int TRIGGER_EVENT_UPDATE = 1; |
97 | public static final int TRIGGER_EVENT_DELETE = 2; |
98 | public static final int TRIGGER_EVENT_INSERT = 4; |
99 | |
100 | |
101 | private UUID id; |
102 | private String name; |
103 | private String oldReferencingName; |
104 | private String newReferencingName; |
105 | private String triggerDefinition; |
106 | private SchemaDescriptor sd; |
107 | private int eventMask; |
108 | private boolean isBefore; |
109 | private boolean isRow; |
110 | private boolean referencingOld; |
111 | private boolean referencingNew; |
112 | private TableDescriptor td; |
113 | private UUID actionSPSId; |
114 | private SPSDescriptor actionSPS; |
115 | private UUID whenSPSId; |
116 | private SPSDescriptor whenSPS; |
117 | private boolean isEnabled; |
118 | private int[] referencedCols; |
119 | private Timestamp creationTimestamp; |
120 | private UUID triggerSchemaId; |
121 | private UUID triggerTableId; |
122 | |
123 | |
124 | /** |
125 | * Niladic constructor, for formatable |
126 | */ |
127 | public TriggerDescriptor() {} |
128 | |
129 | /** |
130 | * Constructor. Used when creating a trigger from SYS.SYSTRIGGERS |
131 | * |
132 | * @param dataDictionary the data dictionary |
133 | * @param sd the schema descriptor for this trigger |
134 | * @param id the trigger id |
135 | * @param name the trigger name |
136 | * @param eventMask TriggerDescriptor.TRIGGER_EVENT_XXXX |
137 | * @param isBefore is this a before (as opposed to after) trigger |
138 | * @param isRow is this a row trigger or statement trigger |
139 | * @param isEnabled is this trigger enabled or disabled |
140 | * @param td the table upon which this trigger is defined |
141 | * @param whenSPSId the sps id for the when clause (may be null) |
142 | * @param actionSPSId the spsid for the trigger action (may be null) |
143 | * @param creationTimestamp when was this trigger created? |
144 | * @param referencedCols what columns does this trigger reference (may be null) |
145 | * @param triggerDefinition The original user text of the trigger action |
146 | * @param referencingOld whether or not OLD appears in REFERENCING clause |
147 | * @param referencingNew whether or not NEW appears in REFERENCING clause |
148 | * @param oldReferencingName old referencing table name, if any, that appears in REFERCING clause |
149 | * @param newReferencingName new referencing table name, if any, that appears in REFERCING clause |
150 | */ |
151 | public TriggerDescriptor |
152 | ( |
153 | DataDictionary dataDictionary, |
154 | SchemaDescriptor sd, |
155 | UUID id, |
156 | String name, |
157 | int eventMask, |
158 | boolean isBefore, |
159 | boolean isRow, |
160 | boolean isEnabled, |
161 | TableDescriptor td, |
162 | UUID whenSPSId, |
163 | UUID actionSPSId, |
164 | Timestamp creationTimestamp, |
165 | int[] referencedCols, |
166 | String triggerDefinition, |
167 | boolean referencingOld, |
168 | boolean referencingNew, |
169 | String oldReferencingName, |
170 | String newReferencingName |
171 | ) |
172 | { |
173 | super(dataDictionary); |
174 | this.id = id; |
175 | this.sd = sd; |
176 | this.name = name; |
177 | this.eventMask = eventMask; |
178 | this.isBefore = isBefore; |
179 | this.isRow = isRow; |
180 | this.td = td; |
181 | this.actionSPSId = actionSPSId; |
182 | this.whenSPSId = whenSPSId; |
183 | this.isEnabled = isEnabled; |
184 | this.referencedCols = referencedCols; |
185 | this.creationTimestamp = creationTimestamp; |
186 | this.triggerDefinition = triggerDefinition; |
187 | this.referencingOld = referencingOld; |
188 | this.referencingNew = referencingNew; |
189 | this.oldReferencingName = oldReferencingName; |
190 | this.newReferencingName = newReferencingName; |
191 | triggerSchemaId = sd.getUUID(); |
192 | triggerTableId = td.getUUID(); |
193 | } |
194 | |
195 | |
196 | /** |
197 | * Get the trigger UUID |
198 | * |
199 | * @return the id |
200 | */ |
201 | public UUID getUUID() |
202 | { |
203 | return id; |
204 | } |
205 | |
206 | /** |
207 | * Get the trigger name |
208 | * |
209 | * @return the name |
210 | */ |
211 | public String getName() |
212 | { |
213 | return name; |
214 | } |
215 | |
216 | public UUID getTableId() { |
217 | return triggerTableId; |
218 | } |
219 | |
220 | /** |
221 | * Get the triggers schema descriptor |
222 | * |
223 | * @return the schema descriptor |
224 | * |
225 | * @exception StandardException on error |
226 | */ |
227 | public SchemaDescriptor getSchemaDescriptor() |
228 | throws StandardException |
229 | { |
230 | if (sd == null) |
231 | { |
232 | sd = getDataDictionary().getSchemaDescriptor(triggerSchemaId, null); |
233 | } |
234 | return sd; |
235 | } |
236 | |
237 | /** |
238 | * Indicate whether this trigger listens for this |
239 | * type of event. |
240 | * |
241 | * @param event TRIGGER_EVENT_XXXX |
242 | * |
243 | * @return true if it listens to the specified event. |
244 | */ |
245 | public boolean listensForEvent(int event) |
246 | { |
247 | return (event & eventMask) == event; |
248 | } |
249 | |
250 | |
251 | /** |
252 | * Get the trigger event mask. Currently, a trigger |
253 | * may only listen for a single event, though it may |
254 | * OR multiple events in the future. |
255 | * |
256 | * @return the trigger event mask |
257 | */ |
258 | public int getTriggerEventMask() |
259 | { |
260 | return eventMask; |
261 | } |
262 | |
263 | /** |
264 | * Get the time that this trigger was created. |
265 | * |
266 | * @return the time the trigger was created |
267 | */ |
268 | public Timestamp getCreationTimestamp() |
269 | { |
270 | return creationTimestamp; |
271 | } |
272 | |
273 | /** |
274 | * Is this a before trigger |
275 | * |
276 | * @return true if it is a before trigger |
277 | */ |
278 | public boolean isBeforeTrigger() |
279 | { |
280 | return isBefore; |
281 | } |
282 | |
283 | /** |
284 | * Is this a row trigger |
285 | * |
286 | * @return true if it is a before trigger |
287 | */ |
288 | public boolean isRowTrigger() |
289 | { |
290 | return isRow; |
291 | } |
292 | |
293 | |
294 | /** |
295 | * Get the trigger action sps UUID |
296 | * |
297 | * @return the uuid of the sps action |
298 | */ |
299 | public UUID getActionId() |
300 | { |
301 | return actionSPSId; |
302 | } |
303 | |
304 | /** |
305 | * Get the trigger action sps |
306 | * |
307 | * @return the trigger action sps |
308 | * |
309 | * @exception StandardException on error |
310 | */ |
311 | public SPSDescriptor getActionSPS(LanguageConnectionContext lcc) |
312 | throws StandardException |
313 | { |
314 | if (actionSPS == null) |
315 | { |
316 | //bug 4821 - do the sysstatement look up in a nested readonly |
317 | //transaction rather than in the user transaction. Because of |
318 | //this, the nested compile transaction which is attempting to |
319 | //compile the trigger will not run into any locking issues with |
320 | //the user transaction for sysstatements. |
321 | lcc.beginNestedTransaction(true); |
322 | actionSPS = getDataDictionary().getSPSDescriptor(actionSPSId); |
323 | lcc.commitNestedTransaction(); |
324 | } |
325 | return actionSPS; |
326 | } |
327 | |
328 | /** |
329 | * Get the trigger when clause sps UUID |
330 | * |
331 | * @return the uuid of the sps action |
332 | */ |
333 | public UUID getWhenClauseId() |
334 | { |
335 | return whenSPSId; |
336 | } |
337 | |
338 | /** |
339 | * Get the trigger when clause sps |
340 | * |
341 | * @return the sps of the when clause |
342 | * |
343 | * @exception StandardException on error |
344 | */ |
345 | public SPSDescriptor getWhenClauseSPS() |
346 | throws StandardException |
347 | { |
348 | if (whenSPS == null) |
349 | { |
350 | whenSPS = getDataDictionary().getSPSDescriptor(whenSPSId); |
351 | } |
352 | return whenSPS; |
353 | } |
354 | |
355 | /** |
356 | * Get the trigger table descriptor |
357 | * |
358 | * @return the table descripor upon which this trigger |
359 | * is declared |
360 | * |
361 | * @exception StandardException on error |
362 | */ |
363 | public TableDescriptor getTableDescriptor() |
364 | throws StandardException |
365 | { |
366 | if (td == null) |
367 | { |
368 | td = getDataDictionary().getTableDescriptor(triggerTableId); |
369 | } |
370 | return td; |
371 | } |
372 | |
373 | /** |
374 | * Get the referenced table descriptor for this trigger. |
375 | * |
376 | * @return the referenced table descriptor |
377 | * |
378 | * @exception StandardException on error |
379 | */ |
380 | // caller converts referencedCols to referencedColsDescriptor... |
381 | // public ReferencedColumns getReferencedColumnsDescriptor() |
382 | // throws StandardException |
383 | // { |
384 | // return (referencedCols == null) ? |
385 | // (ReferencedColumns)null : |
386 | // new ReferencedColumnsDescriptorImpl(referencedCols); |
387 | // } |
388 | |
389 | /** |
390 | * Get the referenced column array for this trigger, used in "alter table |
391 | * drop column", we get the handle and change it |
392 | * |
393 | * @return the referenced column array |
394 | */ |
395 | public int[] getReferencedCols() |
396 | { |
397 | return referencedCols; |
398 | } |
399 | |
400 | /** |
401 | * Is this trigger enabled |
402 | * |
403 | * @return true if it is enabled |
404 | */ |
405 | public boolean isEnabled() |
406 | { |
407 | return isEnabled; |
408 | } |
409 | |
410 | /** |
411 | * Mark this trigger as enabled |
412 | * |
413 | */ |
414 | public void setEnabled() |
415 | { |
416 | isEnabled = true; |
417 | } |
418 | |
419 | /** |
420 | * Mark this trigger as disabled |
421 | * |
422 | */ |
423 | public void setDisabled() |
424 | { |
425 | isEnabled = false; |
426 | } |
427 | |
428 | /** |
429 | * Does this trigger need to fire on this type of |
430 | * DML? |
431 | * |
432 | * @param stmtType the type of DML |
433 | * (StatementType.INSERT|StatementType.UPDATE|StatementType.DELETE) |
434 | * @param modifiedCols the columns modified, or null for all |
435 | * |
436 | * @return true/false |
437 | * |
438 | * @exception StandardException on error |
439 | */ |
440 | public boolean needsToFire(int stmtType, int[] modifiedCols) |
441 | throws StandardException |
442 | { |
443 | |
444 | if (SanityManager.DEBUG) |
445 | { |
446 | if (!((stmtType == StatementType.INSERT) || |
447 | (stmtType == StatementType.BULK_INSERT_REPLACE) || |
448 | (stmtType == StatementType.UPDATE) || |
449 | (stmtType == StatementType.DELETE))) |
450 | { |
451 | SanityManager.THROWASSERT("invalid statement type "+stmtType); |
452 | } |
453 | } |
454 | |
455 | /* |
456 | ** If we are disabled, we never fire |
457 | */ |
458 | if (!isEnabled) |
459 | { |
460 | return false; |
461 | } |
462 | |
463 | if (stmtType == StatementType.INSERT) |
464 | { |
465 | return (eventMask & TRIGGER_EVENT_INSERT) == eventMask; |
466 | } |
467 | if (stmtType == StatementType.DELETE) |
468 | { |
469 | return (eventMask & TRIGGER_EVENT_DELETE) == eventMask; |
470 | } |
471 | |
472 | // this is a temporary restriction, but it may not be lifted |
473 | // anytime soon. |
474 | if (stmtType == StatementType.BULK_INSERT_REPLACE) |
475 | { |
476 | throw StandardException.newException(SQLState.LANG_NO_BULK_INSERT_REPLACE_WITH_TRIGGER, |
477 | getTableDescriptor().getQualifiedName(), name); |
478 | } |
479 | |
480 | // if update, only relevant if columns intersect |
481 | return ((eventMask & TRIGGER_EVENT_UPDATE) == eventMask) && |
482 | ConstraintDescriptor.doColumnsIntersect(modifiedCols, referencedCols); |
483 | } |
484 | |
485 | /** |
486 | * Get the original trigger definition. |
487 | * |
488 | * @return The trigger definition. |
489 | */ |
490 | public String getTriggerDefinition() |
491 | { |
492 | return triggerDefinition; |
493 | } |
494 | |
495 | /** |
496 | * Get whether or not OLD was replaced |
497 | * in the REFERENCING clause. |
498 | * |
499 | * @return Whether or not OLD was replaced |
500 | * in the REFERENCING clause. |
501 | */ |
502 | public boolean getReferencingOld() |
503 | { |
504 | return referencingOld; |
505 | } |
506 | |
507 | /** |
508 | * Get whether or not NEW was replaced |
509 | * in the REFERENCING clause. |
510 | * |
511 | * @return Whether or not NEW was replaced |
512 | * in the REFERENCING clause. |
513 | */ |
514 | public boolean getReferencingNew() |
515 | { |
516 | return referencingNew; |
517 | } |
518 | |
519 | /** |
520 | * Get the old Referencing name, if any, |
521 | * from the REFERENCING clause. |
522 | * |
523 | * @return The old Referencing name, if any, |
524 | * from the REFERENCING clause. |
525 | */ |
526 | public String getOldReferencingName() |
527 | { |
528 | return oldReferencingName; |
529 | } |
530 | |
531 | /** |
532 | * Get the new Referencing name, if any, |
533 | * from the REFERENCING clause. |
534 | * |
535 | * @return The new Referencing name, if any, |
536 | * from the REFERENCING clause. |
537 | */ |
538 | public String getNewReferencingName() |
539 | { |
540 | return newReferencingName; |
541 | } |
542 | |
543 | public String toString() |
544 | { |
545 | if (SanityManager.DEBUG) |
546 | { |
547 | return "TRIGGER: "+name; |
548 | } |
549 | else |
550 | { |
551 | return ""; |
552 | } |
553 | } |
554 | |
555 | //////////////////////////////////////////////////////////////////// |
556 | // |
557 | // PROVIDER INTERFACE |
558 | // |
559 | //////////////////////////////////////////////////////////////////// |
560 | |
561 | /** |
562 | * @return the stored form of this provider |
563 | * |
564 | * @see Dependable#getDependableFinder |
565 | */ |
566 | public DependableFinder getDependableFinder() |
567 | { |
568 | return getDependableFinder(StoredFormatIds.TRIGGER_DESCRIPTOR_FINDER_V01_ID); |
569 | } |
570 | |
571 | /** |
572 | * Return the name of this Provider. (Useful for errors.) |
573 | * |
574 | * @return String The name of this provider. |
575 | */ |
576 | public String getObjectName() |
577 | { |
578 | return name; |
579 | } |
580 | |
581 | /** |
582 | * Get the provider's UUID |
583 | * |
584 | * @return The provider's UUID |
585 | */ |
586 | public UUID getObjectID() |
587 | { |
588 | return id; |
589 | } |
590 | |
591 | /** |
592 | * Get the provider's type. |
593 | * |
594 | * @return char The provider's type. |
595 | */ |
596 | public String getClassType() |
597 | { |
598 | return Dependable.TRIGGER; |
599 | } |
600 | |
601 | ////////////////////////////////////////////////////// |
602 | // |
603 | // DEPENDENT INTERFACE |
604 | // |
605 | // Triggers are dependent on the underlying table, |
606 | // and their spses (for the trigger action and the WHEN |
607 | // clause). |
608 | // |
609 | ////////////////////////////////////////////////////// |
610 | /** |
611 | * Check that all of the dependent's dependencies are valid. |
612 | * |
613 | * @return true if the dependent is currently valid |
614 | */ |
615 | public synchronized boolean isValid() |
616 | { |
617 | return true; |
618 | } |
619 | |
620 | /** |
621 | * Prepare to mark the dependent as invalid (due to at least one of |
622 | * its dependencies being invalid). |
623 | * |
624 | * @param action The action causing the invalidation |
625 | * @param p the provider |
626 | * @param lcc the language connection context |
627 | * |
628 | * @exception StandardException thrown if unable to make it invalid |
629 | */ |
630 | public void prepareToInvalidate |
631 | ( |
632 | Provider p, |
633 | int action, |
634 | LanguageConnectionContext lcc |
635 | ) throws StandardException |
636 | { |
637 | |
638 | |
639 | switch (action) |
640 | { |
641 | /* |
642 | ** We are only dependent on the underlying |
643 | ** table, and our spses. (we should be |
644 | ** dropped before our table is dropped). |
645 | */ |
646 | case DependencyManager.DROP_TABLE: |
647 | case DependencyManager.DROP_SYNONYM: |
648 | case DependencyManager.DROP_SPS: |
649 | case DependencyManager.RENAME: |
650 | DependencyManager dm = getDataDictionary().getDependencyManager(); |
651 | throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, |
652 | dm.getActionString(action), |
653 | p.getObjectName(), "TRIGGER", name); |
654 | |
655 | /* |
656 | ** The trigger descriptor depends on the trigger table. |
657 | ** This means that we get called whenever anything happens |
658 | ** to the trigger table. There are so many cases where this |
659 | ** can happen that it doesn't make sense to have an assertion |
660 | ** here to check whether the action was expected (it makes |
661 | ** the code hard to maintain, and creates a big switch statement). |
662 | */ |
663 | default: |
664 | break; |
665 | } |
666 | } |
667 | |
668 | /** |
669 | * Mark the dependent as invalid (due to at least one of |
670 | * its dependencies being invalid). Always an error |
671 | * for a trigger -- should never have gotten here. |
672 | * |
673 | * @param lcc the language connection context |
674 | * @param action The action causing the invalidation |
675 | * |
676 | * @exception StandardException thrown if called in sanity mode |
677 | */ |
678 | public void makeInvalid(int action, LanguageConnectionContext lcc) throws StandardException |
679 | { |
680 | // No sanity check for valid action. Trigger descriptors depend on |
681 | // the trigger table, so there is a very large number of actions |
682 | // that we would have to check against. This is hard to maintain, |
683 | // so don't bother. |
684 | } |
685 | |
686 | /** |
687 | * Attempt to revalidate the dependent. Meaningless |
688 | * for a trigger. |
689 | * |
690 | * @param lcc the language connection context |
691 | */ |
692 | public void makeValid(LanguageConnectionContext lcc) |
693 | { |
694 | } |
695 | |
696 | |
697 | ////////////////////////////////////////////////////////////// |
698 | // |
699 | // FORMATABLE |
700 | // |
701 | ////////////////////////////////////////////////////////////// |
702 | |
703 | /** |
704 | * Read this object from a stream of stored objects. |
705 | * |
706 | * @param in read this. |
707 | * |
708 | * @exception IOException thrown on error |
709 | * @exception ClassNotFoundException thrown on error |
710 | */ |
711 | public void readExternal(ObjectInput in) |
712 | throws IOException, ClassNotFoundException |
713 | { |
714 | id = (UUID)in.readObject(); |
715 | name = (String)in.readObject(); |
716 | triggerSchemaId = (UUID)in.readObject(); |
717 | triggerTableId = (UUID)in.readObject(); |
718 | eventMask = in.readInt(); |
719 | isBefore = in.readBoolean(); |
720 | isRow = in.readBoolean(); |
721 | isEnabled = in.readBoolean(); |
722 | whenSPSId = (UUID)in.readObject(); |
723 | actionSPSId = (UUID)in.readObject(); |
724 | int length = in.readInt(); |
725 | if (length != 0) |
726 | { |
727 | referencedCols = new int[length]; |
728 | for (int i = 0; i < length; i++) |
729 | { |
730 | referencedCols[i] = in.readInt(); |
731 | } |
732 | } |
733 | triggerDefinition = (String)in.readObject(); |
734 | referencingOld = in.readBoolean(); |
735 | referencingNew = in.readBoolean(); |
736 | oldReferencingName = (String)in.readObject(); |
737 | newReferencingName = (String)in.readObject(); |
738 | |
739 | } |
740 | |
741 | protected DataDictionary getDataDictionary() throws StandardException |
742 | { |
743 | /* |
744 | note: we need to do this since when this trigger is read back from |
745 | disk (when it is associated with a sps), the dataDictionary has not |
746 | been initialized and therefore can give a NullPointerException |
747 | */ |
748 | DataDictionary dd = super.getDataDictionary(); |
749 | if (dd == null) |
750 | { |
751 | LanguageConnectionContext lcc = (LanguageConnectionContext) |
752 | ContextService.getContext(LanguageConnectionContext.CONTEXT_ID); |
753 | dd = lcc.getDataDictionary(); |
754 | setDataDictionary(dd); |
755 | } |
756 | return dd; |
757 | } |
758 | |
759 | /** |
760 | * Write this object to a stream of stored objects. |
761 | * |
762 | * @param out write bytes here. |
763 | * |
764 | * @exception IOException thrown on error |
765 | */ |
766 | public void writeExternal( ObjectOutput out ) |
767 | throws IOException |
768 | { |
769 | if (SanityManager.DEBUG) |
770 | { |
771 | SanityManager.ASSERT(triggerSchemaId != null, |
772 | "triggerSchemaId expected to be non-null"); |
773 | SanityManager.ASSERT(triggerTableId != null, |
774 | "triggerTableId expected to be non-null"); |
775 | } |
776 | out.writeObject(id); |
777 | out.writeObject(name); |
778 | out.writeObject(triggerSchemaId); |
779 | out.writeObject(triggerTableId); |
780 | out.writeInt(eventMask); |
781 | out.writeBoolean(isBefore); |
782 | out.writeBoolean(isRow); |
783 | out.writeBoolean(isEnabled); |
784 | out.writeObject(whenSPSId); |
785 | out.writeObject(actionSPSId); |
786 | if (referencedCols == null) |
787 | { |
788 | out.writeInt(0); |
789 | } |
790 | else |
791 | { |
792 | out.writeInt(referencedCols.length); |
793 | for (int i = 0; i < referencedCols.length; i++) |
794 | { |
795 | out.writeInt(referencedCols[i]); |
796 | } |
797 | } |
798 | out.writeObject(triggerDefinition); |
799 | out.writeBoolean(referencingOld); |
800 | out.writeBoolean(referencingNew); |
801 | out.writeObject(oldReferencingName); |
802 | out.writeObject(newReferencingName); |
803 | } |
804 | |
805 | /** |
806 | * Get the formatID which corresponds to this class. |
807 | * |
808 | * @return the formatID of this class |
809 | */ |
810 | public int getTypeFormatId() { return StoredFormatIds.TRIGGER_DESCRIPTOR_V01_ID; } |
811 | |
812 | /** @see TupleDescriptor#getDescriptorType */ |
813 | public String getDescriptorType() |
814 | { |
815 | return "Trigger"; |
816 | } |
817 | |
818 | /** @see TupleDescriptor#getDescriptorName */ |
819 | public String getDescriptorName() { return name; } |
820 | |
821 | } |
822 | |