📄 updatenode.java
字号:
/* Derby - Class org.apache.derby.impl.sql.compile.UpdateNode Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.impl.sql.compile;import org.apache.derby.iapi.services.context.ContextManager;import org.apache.derby.iapi.services.loader.GeneratedMethod;import org.apache.derby.iapi.services.compiler.MethodBuilder;import org.apache.derby.impl.sql.compile.ActivationClassBuilder;import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;import org.apache.derby.impl.sql.execute.FKInfo;import org.apache.derby.iapi.services.compiler.MethodBuilder;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.sql.compile.CompilerContext;import org.apache.derby.iapi.sql.compile.C_NodeTypes;import org.apache.derby.iapi.sql.compile.Visitable;import org.apache.derby.iapi.sql.compile.Visitor;import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor;import org.apache.derby.iapi.sql.dictionary.DataDictionary;import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;import org.apache.derby.iapi.sql.dictionary.TableDescriptor;import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.sql.execute.ConstantAction;import org.apache.derby.iapi.sql.execute.CursorResultSet;import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;import org.apache.derby.iapi.sql.execute.ExecRow;import org.apache.derby.iapi.sql.Activation;import org.apache.derby.iapi.sql.ResultSet;import org.apache.derby.iapi.sql.StatementType;import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;import org.apache.derby.iapi.store.access.TransactionController;import org.apache.derby.vti.DeferModification;import org.apache.derby.iapi.services.io.FormatableBitSet;import org.apache.derby.iapi.reference.ClassName;import org.apache.derby.iapi.util.ReuseFactory;import org.apache.derby.iapi.services.classfile.VMOpcode;import java.lang.reflect.Modifier;import java.sql.SQLException;import java.util.Properties;import java.util.Vector;/** * An UpdateNode represents an UPDATE statement. It is the top node of the * query tree for that statement. * For positioned update, there may be no from table specified. * The from table will be derived from the cursor specification of * the named cursor. * * @author Jeff Lichtman */public final class UpdateNode extends DMLModStatementNode{ //Note: These are public so they will be visible to //the RepUpdateNode. public int[] changedColumnIds; public ExecRow emptyHeapRow; public boolean deferred; public ValueNode checkConstraints; public FKInfo fkInfo; protected FromTable targetTable; protected FormatableBitSet readColsBitSet; protected boolean positionedUpdate; /* Column name for the RowLocation in the ResultSet */ public static final String COLUMNNAME = "###RowLocationToUpdate"; /** * Initializer for an UpdateNode. * * @param targetTableName The name of the table to update * @param resultSet The ResultSet that will generate * the rows to update from the given table */ public void init( Object targetTableName, Object resultSet) { super.init(resultSet); this.targetTableName = (TableName) targetTableName; } /** * Convert this object to a String. See comments in QueryTreeNode.java * for how this should be done for tree printing. * * @return This object as a String */ public String toString() { if (SanityManager.DEBUG) { return targetTableName.toString() + "\n" + super.toString(); } else { return ""; } } public String statementToString() { return "UPDATE"; } /** * Prints the sub-nodes of this object. See QueryTreeNode.java for * how tree printing is supposed to work. * * @param depth The depth of this node in the tree * * @return Nothing */ public void printSubNodes(int depth) { if (SanityManager.DEBUG) { super.printSubNodes(depth); if (targetTableName != null) { printLabel(depth, "targetTableName: "); targetTableName.treePrint(depth + 1); } /* RESOLVE - need to print out targetTableDescriptor */ } } /** * Bind this UpdateNode. This means looking up tables and columns and * getting their types, and figuring out the result types of all * expressions, as well as doing view resolution, permissions checking, * etc. * <p> * Binding an update will also massage the tree so that * the ResultSetNode has a set of columns to contain the old row * value, followed by a set of columns to contain the new row * value, followed by a column to contain the RowLocation of the * row to be updated. * * @return The bound query tree * * @exception StandardException Thrown on error */ public QueryTreeNode bind() throws StandardException { FromList fromList = (FromList) getNodeFactory().getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager()); ResultColumn rowLocationColumn = null; ValueNode rowLocationNode = null; TableName cursorTargetTableName = null; CurrentOfNode currentOfNode = null; FromList resultFromList; ResultColumnList afterColumns = null; DataDictionary dataDictionary = getDataDictionary(); // check if targetTable is a synonym if (targetTableName != null) { TableName synonymTab = resolveTableToSynonym(this.targetTableName); if (synonymTab != null) this.targetTableName = synonymTab; } bindTables(dataDictionary); // wait to bind named target table until the cursor // binding is done, so that we can get it from the // cursor if this is a positioned update. // for positioned update, get the cursor's target table. if (SanityManager.DEBUG) { SanityManager.ASSERT((resultSet!=null && resultSet instanceof SelectNode), "Update must have a select result set"); } SelectNode sel; sel = (SelectNode)resultSet; targetTable = (FromTable) sel.fromList.elementAt(0); if (targetTable instanceof CurrentOfNode) { positionedUpdate = true; currentOfNode = (CurrentOfNode) targetTable; cursorTargetTableName = currentOfNode.getBaseCursorTargetTableName(); // instead of an assert, we might say the cursor is not updatable. if (SanityManager.DEBUG) { SanityManager.ASSERT(cursorTargetTableName != null); } } if (targetTable instanceof FromVTI) { targetVTI = (FromVTI) targetTable; targetVTI.setTarget(); } else { // positioned update can leave off the target table. // we get it from the cursor supplying the position. if (targetTableName == null) { // verify we have current of if (SanityManager.DEBUG) SanityManager.ASSERT(cursorTargetTableName!=null); targetTableName = cursorTargetTableName; } // for positioned update, we need to verify that // the named table is the same as the cursor's target. else if (cursorTargetTableName != null) { // this match requires that the named table in the update // be the same as a correlation name in the cursor. if ( !targetTableName.equals(cursorTargetTableName)) { throw StandardException.newException(SQLState.LANG_CURSOR_UPDATE_MISMATCH, targetTableName, currentOfNode.getCursorName()); } } // because we verified that the tables match // and we already bound the cursor or the select, // the table descriptor should always be found. verifyTargetTable(); } /* OVERVIEW - We generate a new ResultColumn, CurrentRowLocation(), and * prepend it to the beginning of the source ResultColumnList. This * will tell us which row(s) to update at execution time. However, * we must defer prepending this generated column until the other * ResultColumns are bound since there will be no ColumnDescriptor * for the generated column. Thus, the sequence of actions is: * * o Bind existing ResultColumnList (columns in SET clause) * o If this is a positioned update with a FOR UPDATE OF list, * then verify that all of the target columns are in the * FOR UPDATE OF list. * o Get the list of indexes that need to be updated. * o Create a ResultColumnList of all the columns in the target * table - this represents the old row. * o If we don't know which columns are being updated, * expand the original ResultColumnList to include all the * columns in the target table, and sort it to be in the * order of the columns in the target table. This represents * the new row. Append it to the ResultColumnList representing * the old row. * o Construct the changedColumnIds array sorted by column position. * o Generate the read column bit map and append any columns * needed for index maint, etc. * o Generate a new ResultColumn for CurrentRowLocation() and * mark it as a generated column. * o Append the new ResultColumn to the ResultColumnList * (This must be done before binding the expressions, so * that the proper type info gets propagated to the new * ResultColumn.) * o Bind the expressions. * o Bind the generated ResultColumn. */ /* Verify that all underlying ResultSets reclaimed their FromList */ if (SanityManager.DEBUG) { SanityManager.ASSERT(fromList.size() == 0, "fromList.size() is expected to be 0, not " + fromList.size() + " on return from RS.bindExpressions()"); } /* ** The current result column list is the one supplied by the user. ** Mark these columns as "updated", so we can tell later which ** columns are really being updated, and which have been added ** but are not really being updated. */ resultSet.getResultColumns().markUpdated(); /* Prepend CurrentRowLocation() to the select's result column list. */ if (SanityManager.DEBUG) SanityManager.ASSERT((resultSet.resultColumns != null), "resultColumns is expected not to be null at bind time"); /* ** Get the result FromTable, which should be the only table in the ** from list.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -