001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.TriggerEventActivator
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.execute;
023:
024: import org.apache.derby.iapi.services.sanity.SanityManager;
025: import org.apache.derby.iapi.error.StandardException;
026:
027: import org.apache.derby.iapi.sql.execute.CursorResultSet;
028: import org.apache.derby.iapi.sql.execute.NoPutResultSet;
029: import org.apache.derby.iapi.sql.execute.ExecRow;
030: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
031: import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor;
032:
033: import org.apache.derby.iapi.sql.Activation;
034:
035: import org.apache.derby.iapi.store.access.TransactionController;
036: import org.apache.derby.impl.sql.execute.AutoincrementCounter;
037: import org.apache.derby.iapi.reference.SQLState;
038: import org.apache.derby.iapi.jdbc.ConnectionContext;
039: import org.apache.derby.catalog.UUID;
040:
041: import java.util.Vector;
042: import java.sql.SQLException;
043:
044: /**
045: * Responsible for firing a trigger or set of triggers
046: * based on an event.
047: */
048: public class TriggerEventActivator {
049: private LanguageConnectionContext lcc;
050: private TransactionController tc;
051: private TriggerInfo triggerInfo;
052: private InternalTriggerExecutionContext tec;
053: private GenericTriggerExecutor[][] executors;
054: private Activation activation;
055: private ConnectionContext cc;
056: private String statementText;
057: private int dmlType;
058: private UUID tableId;
059: private String tableName;
060: private Vector aiCounters;
061:
062: /**
063: * Basic constructor
064: *
065: * @param lcc the lcc
066: * @param tc the xact controller
067: * @param triggerInfo the trigger information
068: * @param dmlType Type of DML for which this trigger is being fired.
069: * @param activation the activation.
070: * @param aiCounters vector of ai counters
071: *
072: * @exception StandardException on error
073: */
074: public TriggerEventActivator(LanguageConnectionContext lcc,
075: TransactionController tc, UUID tableId,
076: TriggerInfo triggerInfo, int dmlType,
077: Activation activation, Vector aiCounters)
078: throws StandardException {
079: if (triggerInfo == null) {
080: return;
081: }
082:
083: // extrapolate the table name from the triggerdescriptors
084: tableName = triggerInfo.triggerArray[0].getTableDescriptor()
085: .getQualifiedName();
086:
087: this .lcc = lcc;
088: this .tc = tc;
089: this .activation = activation;
090: this .tableId = tableId;
091: this .dmlType = dmlType;
092: this .triggerInfo = triggerInfo;
093:
094: cc = (ConnectionContext) lcc.getContextManager().getContext(
095: ConnectionContext.CONTEXT_ID);
096:
097: this .statementText = lcc.getStatementContext()
098: .getStatementText();
099:
100: this .tec = ((GenericExecutionFactory) lcc
101: .getLanguageConnectionFactory().getExecutionFactory())
102: .getTriggerExecutionContext(lcc, cc, statementText,
103: dmlType, triggerInfo.columnIds,
104: triggerInfo.columnNames, tableId, tableName,
105: aiCounters);
106:
107: setupExecutors(triggerInfo);
108: }
109:
110: /**
111: * Reopen the trigger activator. Just creates a new trigger execution
112: * context. Note that close() still must be called when you
113: * are done -- you cannot just do a reopen() w/o a first doing
114: * a close.
115: *
116: * @exception StandardException on error
117: */
118: void reopen() throws StandardException {
119: this .tec = ((GenericExecutionFactory) lcc
120: .getLanguageConnectionFactory().getExecutionFactory())
121: .getTriggerExecutionContext(lcc, cc, statementText,
122: dmlType, triggerInfo.columnIds,
123: triggerInfo.columnNames, tableId, tableName,
124: aiCounters);
125: setupExecutors(triggerInfo);
126: }
127:
128: private void setupExecutors(TriggerInfo triggerInfo)
129: throws StandardException {
130: executors = new GenericTriggerExecutor[TriggerEvent.MAX_EVENTS][];
131: Vector[] executorLists = new Vector[TriggerEvent.MAX_EVENTS];
132: for (int i = 0; i < TriggerEvent.MAX_EVENTS; i++) {
133: executorLists[i] = new Vector();
134: }
135:
136: for (int i = 0; i < triggerInfo.triggerArray.length; i++) {
137: TriggerDescriptor td = triggerInfo.triggerArray[i];
138: switch (td.getTriggerEventMask()) {
139: case TriggerDescriptor.TRIGGER_EVENT_INSERT:
140: if (td.isBeforeTrigger()) {
141: executorLists[TriggerEvent.BEFORE_INSERT]
142: .addElement(td);
143: } else {
144: executorLists[TriggerEvent.AFTER_INSERT]
145: .addElement(td);
146: }
147: break;
148:
149: case TriggerDescriptor.TRIGGER_EVENT_DELETE:
150: if (td.isBeforeTrigger()) {
151: executorLists[TriggerEvent.BEFORE_DELETE]
152: .addElement(td);
153: } else {
154: executorLists[TriggerEvent.AFTER_DELETE]
155: .addElement(td);
156: }
157: break;
158:
159: case TriggerDescriptor.TRIGGER_EVENT_UPDATE:
160: if (td.isBeforeTrigger()) {
161: executorLists[TriggerEvent.BEFORE_UPDATE]
162: .addElement(td);
163: } else {
164: executorLists[TriggerEvent.AFTER_UPDATE]
165: .addElement(td);
166: }
167: break;
168: default:
169: if (SanityManager.DEBUG) {
170: SanityManager.THROWASSERT("bad trigger event "
171: + td.getTriggerEventMask());
172: }
173: }
174: }
175:
176: for (int i = 0; i < executorLists.length; i++) {
177: int size = executorLists[i].size();
178: if (size > 0) {
179: executors[i] = new GenericTriggerExecutor[size];
180: for (int j = 0; j < size; j++) {
181: TriggerDescriptor td = (TriggerDescriptor) executorLists[i]
182: .elementAt(j);
183: executors[i][j] = (td.isRowTrigger()) ? (GenericTriggerExecutor) new RowTriggerExecutor(
184: tec, td, activation, lcc)
185: : (GenericTriggerExecutor) new StatementTriggerExecutor(
186: tec, td, activation, lcc);
187: }
188: }
189: }
190: }
191:
192: /**
193: * Handle the given event.
194: *
195: * @param event a trigger event
196: * @param brs the before result set. Typically
197: * a TemporaryRowHolderResultSet but sometimes a
198: * BulkTableScanResultSet
199: * @param ars the after result set. Typically
200: * a TemporaryRowHolderResultSet but sometimes a
201: * BulkTableScanResultSet
202: *
203: * @exception StandardException on error
204: */
205: public void notifyEvent(TriggerEvent event, CursorResultSet brs,
206: CursorResultSet ars) throws StandardException {
207: if (executors == null) {
208: return;
209: }
210:
211: int eventNumber = event.getNumber();
212: if (executors[eventNumber] == null) {
213: return;
214: }
215:
216: tec.setCurrentTriggerEvent(event);
217: try {
218: if (brs != null) {
219: brs.open();
220: }
221: if (ars != null) {
222: ars.open();
223: }
224:
225: lcc.pushExecutionStmtValidator(tec);
226: for (int i = 0; i < executors[eventNumber].length; i++) {
227: if (i > 0) {
228:
229: if (brs != null) {
230: ((NoPutResultSet) brs).reopenCore();
231: }
232: if (ars != null) {
233: ((NoPutResultSet) ars).reopenCore();
234: }
235: }
236: // Reset the AI counters to the beginning before firing next
237: // trigger.
238: tec.resetAICounters(true);
239: executors[eventNumber][i].fireTrigger(event, brs, ars);
240: }
241: } finally {
242: lcc.popExecutionStmtValidator(tec);
243: tec.clearCurrentTriggerEvent();
244: }
245: }
246:
247: /**
248: * Clean up and release resources.
249: *
250: * @exception StandardException on unexpected error
251: */
252: public void cleanup() throws StandardException {
253: if (tec != null) {
254: tec.cleanup();
255: }
256: }
257: }
|