001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.VTIDeferModPolicy
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.compile;
023:
024: import org.apache.derby.iapi.error.StandardException;
025: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
026: import org.apache.derby.iapi.sql.compile.Visitor;
027: import org.apache.derby.iapi.sql.compile.Visitable;
028:
029: import org.apache.derby.vti.DeferModification;
030:
031: import java.util.Enumeration;
032: import java.util.Hashtable;
033:
034: import java.sql.ResultSet;
035: import java.sql.SQLException;
036:
037: /**
038: * This class applies a VTI modification deferral policy to a statement to
039: * see whether it should be deferred.
040: */
041: class VTIDeferModPolicy implements Visitor {
042: /**
043: * See if a VTI modification statement should be deferred.
044: *
045: * @param statementType DeferModification.INSERT_STATEMENT, UPDATE_STATEMENT, or DELETE_STATEMENT
046: * @param targetVTI The target VTI
047: * @param updateColumnNames The list of columns being updated, null if this is not an update statement
048: * @param source
049: */
050: public static boolean deferIt(int statementType, FromVTI targetVTI,
051: String[] updateColumnNames, QueryTreeNode source)
052: throws StandardException {
053: try {
054: DeferModification deferralControl;
055: int resultSetType = targetVTI.getResultSetType();
056:
057: /* Deferred updates and deletes are implemented by scrolling the result set. So, if
058: * the statement is an update or delete but the result set is not scrollable then do
059: * not attempt to defer the statement.
060: */
061: if ((statementType == DeferModification.UPDATE_STATEMENT || statementType == DeferModification.DELETE_STATEMENT)
062: && resultSetType == ResultSet.TYPE_FORWARD_ONLY)
063: return false;
064:
065: deferralControl = targetVTI.getDeferralControl();
066: if (deferralControl == null) {
067: String VTIClassName = targetVTI.getNewInvocation()
068: .getJavaClassName();
069: deferralControl = new DefaultVTIModDeferPolicy(
070: VTIClassName,
071: ResultSet.TYPE_SCROLL_SENSITIVE == resultSetType);
072: }
073: if (deferralControl.alwaysDefer(statementType))
074: return true;
075:
076: if (source == null
077: && statementType != DeferModification.UPDATE_STATEMENT)
078: return false;
079:
080: VTIDeferModPolicy deferralSearch = new VTIDeferModPolicy(
081: targetVTI, updateColumnNames, deferralControl,
082: statementType);
083:
084: if (source != null)
085: source.accept(deferralSearch);
086:
087: if (statementType == DeferModification.UPDATE_STATEMENT) {
088: // Apply the columnRequiresDefer method to updated columns not in the where clause.
089: Enumeration columns = deferralSearch.columns.keys();
090: while (columns.hasMoreElements()) {
091: if (deferralControl.columnRequiresDefer(
092: statementType, (String) columns
093: .nextElement(), false))
094: return true;
095: }
096: }
097: return deferralSearch.deferred;
098: } catch (SQLException sqle) {
099: throw StandardException.unexpectedUserException(sqle);
100: }
101: } // end of deferIt
102:
103: // state needed to search the statement parse tree for nodes that require deferred modification
104: private boolean deferred = false;
105: private DeferModification deferralControl;
106: private int statementType;
107: private int tableNumber;
108: private Hashtable columns = new Hashtable();
109:
110: private VTIDeferModPolicy(FromVTI targetVTI, String[] columnNames,
111: DeferModification deferralControl, int statementType) {
112: this .deferralControl = deferralControl;
113: this .statementType = statementType;
114: tableNumber = targetVTI.getTableNumber();
115: if (statementType == DeferModification.UPDATE_STATEMENT
116: && columnNames != null) {
117: for (int i = 0; i < columnNames.length; i++)
118: columns.put(columnNames[i], columnNames[i]);
119: }
120: }
121:
122: public Visitable visit(Visitable node) throws StandardException {
123: try {
124: if (node instanceof ColumnReference
125: && statementType != DeferModification.INSERT_STATEMENT) {
126: ColumnReference cr = (ColumnReference) node;
127: if (cr.getTableNumber() == tableNumber) {
128: String columnName = cr.getColumnName();
129: if (statementType == DeferModification.DELETE_STATEMENT) {
130: if (columns.get(columnName) == null) {
131: columns.put(columnName, columnName);
132: if (deferralControl.columnRequiresDefer(
133: statementType, columnName, true))
134: deferred = true;
135: }
136: } else if (statementType == DeferModification.UPDATE_STATEMENT) {
137: if (columns.get(columnName) != null) {
138: // This column is referenced in the where clause and is being updated
139: if (deferralControl.columnRequiresDefer(
140: statementType, columnName, true))
141: deferred = true;
142: columns.remove(columnName); // Only test it once.
143: }
144: }
145: }
146: } else if (node instanceof SelectNode) {
147: SelectNode subSelect = (SelectNode) node;
148: FromList fromList = subSelect.getFromList();
149:
150: for (int i = 0; i < fromList.size(); i++) {
151: FromTable fromTable = (FromTable) fromList
152: .elementAt(i);
153: if (fromTable instanceof FromBaseTable) {
154: TableDescriptor td = fromTable
155: .getTableDescriptor();
156: if (deferralControl.subselectRequiresDefer(
157: statementType, td.getSchemaName(), td
158: .getName()))
159: deferred = true;
160: } else if (fromTable instanceof FromVTI) {
161: FromVTI fromVTI = (FromVTI) fromTable;
162: if (deferralControl.subselectRequiresDefer(
163: statementType, fromVTI
164: .getNewInvocation()
165: .getJavaClassName()))
166: deferred = true;
167: }
168: }
169: }
170: } catch (SQLException sqle) {
171: throw StandardException.unexpectedUserException(sqle);
172: }
173: return node;
174: } // end of visit
175:
176: public boolean stopTraversal() {
177: return deferred;
178: } // end of stopTraversal
179:
180: public boolean skipChildren(Visitable node) {
181: return false;
182: } // end of skipChildren
183: } // end of class VTIDeferModPolicy
|