--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.VTIDeferModPolicy\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.compile;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+\r
+import org.apache.derby.vti.DeferModification;\r
+\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+\r
+import java.sql.ResultSet;\r
+import java.sql.SQLException;\r
+\r
+/**\r
+ * This class applies a VTI modification deferral policy to a statement to\r
+ * see whether it should be deferred.\r
+ */\r
+class VTIDeferModPolicy implements Visitor\r
+{\r
+ /**\r
+ * See if a VTI modification statement should be deferred.\r
+ *\r
+ * @param statementType DeferModification.INSERT_STATEMENT, UPDATE_STATEMENT, or DELETE_STATEMENT\r
+ * @param targetVTI The target VTI\r
+ * @param updateColumnNames The list of columns being updated, null if this is not an update statement\r
+ * @param source\r
+ */\r
+ public static boolean deferIt( int statementType,\r
+ FromVTI targetVTI,\r
+ String[] updateColumnNames,\r
+ QueryTreeNode source)\r
+ throws StandardException\r
+ {\r
+ try\r
+ {\r
+ DeferModification deferralControl;\r
+ int resultSetType = targetVTI.getResultSetType( );\r
+\r
+ /* Deferred updates and deletes are implemented by scrolling the result set. So, if\r
+ * the statement is an update or delete but the result set is not scrollable then do\r
+ * not attempt to defer the statement.\r
+ */\r
+ if( (statementType == DeferModification.UPDATE_STATEMENT ||statementType == DeferModification.DELETE_STATEMENT)\r
+ && resultSetType == ResultSet.TYPE_FORWARD_ONLY)\r
+ return false;\r
+\r
+ deferralControl = targetVTI.getDeferralControl();\r
+ if( deferralControl == null)\r
+ {\r
+ String VTIClassName = targetVTI.getNewInvocation().getJavaClassName();\r
+ deferralControl = new DefaultVTIModDeferPolicy( VTIClassName,\r
+ ResultSet.TYPE_SCROLL_SENSITIVE == resultSetType);\r
+ }\r
+ if( deferralControl.alwaysDefer( statementType))\r
+ return true;\r
+\r
+ if( source == null && statementType != DeferModification.UPDATE_STATEMENT)\r
+ return false;\r
+\r
+ VTIDeferModPolicy deferralSearch = new VTIDeferModPolicy( targetVTI,\r
+ updateColumnNames,\r
+ deferralControl,\r
+ statementType);\r
+\r
+ if( source != null)\r
+ source.accept( deferralSearch);\r
+\r
+ if( statementType == DeferModification.UPDATE_STATEMENT)\r
+ {\r
+ // Apply the columnRequiresDefer method to updated columns not in the where clause.\r
+ Enumeration columns = deferralSearch.columns.keys();\r
+ while( columns.hasMoreElements())\r
+ {\r
+ if( deferralControl.columnRequiresDefer( statementType,\r
+ (String) columns.nextElement(),\r
+ false))\r
+ return true;\r
+ }\r
+ }\r
+ return deferralSearch.deferred;\r
+ }\r
+ catch( SQLException sqle)\r
+ {\r
+ throw StandardException.unexpectedUserException(sqle);\r
+ }\r
+ } // end of deferIt\r
+\r
+ // state needed to search the statement parse tree for nodes that require deferred modification\r
+ private boolean deferred = false;\r
+ private DeferModification deferralControl;\r
+ private int statementType;\r
+ private int tableNumber;\r
+ private Hashtable columns = new Hashtable();\r
+\r
+ private VTIDeferModPolicy( FromVTI targetVTI,\r
+ String[] columnNames,\r
+ DeferModification deferralControl,\r
+ int statementType)\r
+ {\r
+ this.deferralControl = deferralControl;\r
+ this.statementType = statementType;\r
+ tableNumber = targetVTI.getTableNumber();\r
+ if( statementType == DeferModification.UPDATE_STATEMENT && columnNames != null)\r
+ {\r
+ for( int i = 0; i < columnNames.length; i++)\r
+ columns.put( columnNames[i], columnNames[i]);\r
+ }\r
+ }\r
+\r
+ public Visitable visit(Visitable node)\r
+ throws StandardException\r
+ {\r
+ try\r
+ {\r
+ if( node instanceof ColumnReference && statementType != DeferModification.INSERT_STATEMENT)\r
+ {\r
+ ColumnReference cr = (ColumnReference) node;\r
+ if( cr.getTableNumber() == tableNumber)\r
+ {\r
+ String columnName = cr.getColumnName();\r
+ if( statementType == DeferModification.DELETE_STATEMENT)\r
+ {\r
+ if( columns.get( columnName) == null)\r
+ {\r
+ columns.put( columnName, columnName);\r
+ if( deferralControl.columnRequiresDefer( statementType, columnName, true))\r
+ deferred = true;\r
+ }\r
+ }\r
+ else if( statementType == DeferModification.UPDATE_STATEMENT)\r
+ {\r
+ if( columns.get( columnName) != null)\r
+ {\r
+ // This column is referenced in the where clause and is being updated\r
+ if( deferralControl.columnRequiresDefer( statementType, columnName, true))\r
+ deferred = true;\r
+ columns.remove( columnName); // Only test it once.\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else if( node instanceof SelectNode)\r
+ {\r
+ SelectNode subSelect = (SelectNode) node;\r
+ FromList fromList = subSelect.getFromList();\r
+\r
+ for( int i = 0; i < fromList.size(); i++)\r
+ {\r
+ FromTable fromTable = (FromTable) fromList.elementAt(i);\r
+ if( fromTable instanceof FromBaseTable)\r
+ {\r
+ TableDescriptor td = fromTable.getTableDescriptor();\r
+ if( deferralControl.subselectRequiresDefer( statementType,\r
+ td.getSchemaName(),\r
+ td.getName()))\r
+ deferred = true;\r
+ }\r
+ else if( fromTable instanceof FromVTI)\r
+ {\r
+ FromVTI fromVTI = (FromVTI) fromTable;\r
+ if( deferralControl.subselectRequiresDefer( statementType,\r
+ fromVTI.getNewInvocation().getJavaClassName()))\r
+ deferred = true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ catch( SQLException sqle)\r
+ {\r
+ throw StandardException.unexpectedUserException(sqle);\r
+ }\r
+ return node;\r
+ } // end of visit\r
+ \r
+ public boolean stopTraversal()\r
+ {\r
+ return deferred;\r
+ } // end of stopTraversal\r
+ \r
+ public boolean skipChildren(Visitable node)\r
+ {\r
+ return false;\r
+ } // end of skipChildren\r
+} // end of class VTIDeferModPolicy\r