Source Code Cross Referenced for UpdateNode.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » sql » compile » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.impl.sql.compile 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.sql.compile.UpdateNode
0004:
0005:           Licensed to the Apache Software Foundation (ASF) under one or more
0006:           contributor license agreements.  See the NOTICE file distributed with
0007:           this work for additional information regarding copyright ownership.
0008:           The ASF licenses this file to you under the Apache License, Version 2.0
0009:           (the "License"); you may not use this file except in compliance with
0010:           the License.  You may obtain a copy of the License at
0011:
0012:              http://www.apache.org/licenses/LICENSE-2.0
0013:
0014:           Unless required by applicable law or agreed to in writing, software
0015:           distributed under the License is distributed on an "AS IS" BASIS,
0016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:           See the License for the specific language governing permissions and
0018:           limitations under the License.
0019:
0020:         */
0021:
0022:        package org.apache.derby.impl.sql.compile;
0023:
0024:        import org.apache.derby.iapi.services.context.ContextManager;
0025:
0026:        import org.apache.derby.iapi.services.loader.GeneratedMethod;
0027:
0028:        import org.apache.derby.iapi.services.compiler.MethodBuilder;
0029:
0030:        import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
0031:        import org.apache.derby.iapi.sql.conn.Authorizer;
0032:        import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0033:        import org.apache.derby.impl.sql.execute.FKInfo;
0034:        import org.apache.derby.iapi.services.compiler.MethodBuilder;
0035:
0036:        import org.apache.derby.iapi.services.sanity.SanityManager;
0037:        import org.apache.derby.iapi.error.StandardException;
0038:        import org.apache.derby.iapi.sql.compile.CompilerContext;
0039:        import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0040:        import org.apache.derby.iapi.sql.compile.Visitable;
0041:        import org.apache.derby.iapi.sql.compile.Visitor;
0042:
0043:        import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0044:
0045:        import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
0046:        import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
0047:        import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
0048:        import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor;
0049:        import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0050:        import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
0051:        import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0052:        import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList;
0053:
0054:        import org.apache.derby.iapi.reference.SQLState;
0055:        import org.apache.derby.iapi.sql.execute.ConstantAction;
0056:        import org.apache.derby.iapi.sql.execute.CursorResultSet;
0057:        import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
0058:        import org.apache.derby.iapi.sql.execute.ExecRow;
0059:
0060:        import org.apache.derby.iapi.sql.Activation;
0061:        import org.apache.derby.iapi.sql.ResultSet;
0062:        import org.apache.derby.iapi.sql.StatementType;
0063:
0064:        import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
0065:        import org.apache.derby.iapi.store.access.TransactionController;
0066:
0067:        import org.apache.derby.vti.DeferModification;
0068:
0069:        import org.apache.derby.iapi.services.io.FormatableBitSet;
0070:        import org.apache.derby.iapi.reference.ClassName;
0071:
0072:        import org.apache.derby.iapi.util.ReuseFactory;
0073:        import org.apache.derby.iapi.services.classfile.VMOpcode;
0074:
0075:        import java.lang.reflect.Modifier;
0076:        import java.sql.SQLException;
0077:        import java.util.Properties;
0078:        import java.util.Vector;
0079:
0080:        /**
0081:         * An UpdateNode represents an UPDATE statement.  It is the top node of the
0082:         * query tree for that statement.
0083:         * For positioned update, there may be no from table specified.
0084:         * The from table will be derived from the cursor specification of
0085:         * the named cursor.
0086:         *
0087:         * @author Jeff Lichtman
0088:         */
0089:
0090:        public final class UpdateNode extends DMLModStatementNode {
0091:            //Note: These are public so they will be visible to
0092:            //the RepUpdateNode.
0093:            public int[] changedColumnIds;
0094:            public ExecRow emptyHeapRow;
0095:            public boolean deferred;
0096:            public ValueNode checkConstraints;
0097:            public FKInfo fkInfo;
0098:
0099:            protected FromTable targetTable;
0100:            protected FormatableBitSet readColsBitSet;
0101:            protected boolean positionedUpdate;
0102:
0103:            /* Column name for the RowLocation in the ResultSet */
0104:            public static final String COLUMNNAME = "###RowLocationToUpdate";
0105:
0106:            /**
0107:             * Initializer for an UpdateNode.
0108:             *
0109:             * @param targetTableName	The name of the table to update
0110:             * @param resultSet		The ResultSet that will generate
0111:             *				the rows to update from the given table
0112:             */
0113:
0114:            public void init(Object targetTableName, Object resultSet) {
0115:                super .init(resultSet);
0116:                this .targetTableName = (TableName) targetTableName;
0117:            }
0118:
0119:            /**
0120:             * Convert this object to a String.  See comments in QueryTreeNode.java
0121:             * for how this should be done for tree printing.
0122:             *
0123:             * @return	This object as a String
0124:             */
0125:
0126:            public String toString() {
0127:                if (SanityManager.DEBUG) {
0128:                    return targetTableName.toString() + "\n" + super .toString();
0129:                } else {
0130:                    return "";
0131:                }
0132:            }
0133:
0134:            public String statementToString() {
0135:                return "UPDATE";
0136:            }
0137:
0138:            /**
0139:             * Prints the sub-nodes of this object.  See QueryTreeNode.java for
0140:             * how tree printing is supposed to work.
0141:             *
0142:             * @param depth		The depth of this node in the tree
0143:             */
0144:
0145:            public void printSubNodes(int depth) {
0146:                if (SanityManager.DEBUG) {
0147:                    super .printSubNodes(depth);
0148:
0149:                    if (targetTableName != null) {
0150:                        printLabel(depth, "targetTableName: ");
0151:                        targetTableName.treePrint(depth + 1);
0152:                    }
0153:
0154:                    /* RESOLVE - need to print out targetTableDescriptor */
0155:                }
0156:            }
0157:
0158:            /**
0159:             * Bind this UpdateNode.  This means looking up tables and columns and
0160:             * getting their types, and figuring out the result types of all
0161:             * expressions, as well as doing view resolution, permissions checking,
0162:             * etc.
0163:             * <p>
0164:             * Binding an update will also massage the tree so that
0165:             * the ResultSetNode has a set of columns to contain the old row
0166:             * value, followed by a set of columns to contain the new row
0167:             * value, followed by a column to contain the RowLocation of the
0168:             * row to be updated.
0169:             *
0170:             * @return	The bound query tree
0171:             *
0172:             * @exception StandardException		Thrown on error
0173:             */
0174:
0175:            public QueryTreeNode bind() throws StandardException {
0176:                // We just need select privilege on the expressions
0177:                getCompilerContext()
0178:                        .pushCurrentPrivType(Authorizer.SELECT_PRIV);
0179:
0180:                FromList fromList = (FromList) getNodeFactory().getNode(
0181:                        C_NodeTypes.FROM_LIST,
0182:                        getNodeFactory().doJoinOrderOptimization(),
0183:                        getContextManager());
0184:                ResultColumn rowLocationColumn = null;
0185:                ValueNode rowLocationNode = null;
0186:                TableName cursorTargetTableName = null;
0187:                CurrentOfNode currentOfNode = null;
0188:                FromList resultFromList;
0189:                ResultColumnList afterColumns = null;
0190:
0191:                DataDictionary dataDictionary = getDataDictionary();
0192:
0193:                // check if targetTable is a synonym
0194:                if (targetTableName != null) {
0195:                    TableName synonymTab = resolveTableToSynonym(this .targetTableName);
0196:                    if (synonymTab != null) {
0197:                        this .synonymTableName = targetTableName;
0198:                        this .targetTableName = synonymTab;
0199:                    }
0200:                }
0201:
0202:                bindTables(dataDictionary);
0203:
0204:                // wait to bind named target table until the cursor
0205:                // binding is done, so that we can get it from the
0206:                // cursor if this is a positioned update.
0207:
0208:                // for positioned update, get the cursor's target table.
0209:                if (SanityManager.DEBUG) {
0210:                    SanityManager
0211:                            .ASSERT(
0212:                                    (resultSet != null && resultSet instanceof  SelectNode),
0213:                                    "Update must have a select result set");
0214:                }
0215:
0216:                SelectNode sel;
0217:                sel = (SelectNode) resultSet;
0218:                targetTable = (FromTable) sel.fromList.elementAt(0);
0219:
0220:                if (targetTable instanceof  CurrentOfNode) {
0221:                    positionedUpdate = true;
0222:                    currentOfNode = (CurrentOfNode) targetTable;
0223:                    cursorTargetTableName = currentOfNode
0224:                            .getBaseCursorTargetTableName();
0225:
0226:                    // instead of an assert, we might say the cursor is not updatable.
0227:                    if (SanityManager.DEBUG) {
0228:                        SanityManager.ASSERT(cursorTargetTableName != null);
0229:                    }
0230:                }
0231:
0232:                if (targetTable instanceof  FromVTI) {
0233:                    targetVTI = (FromVTI) targetTable;
0234:                    targetVTI.setTarget();
0235:                } else {
0236:                    // positioned update can leave off the target table.
0237:                    // we get it from the cursor supplying the position.
0238:                    if (targetTableName == null) {
0239:                        // verify we have current of
0240:                        if (SanityManager.DEBUG)
0241:                            SanityManager.ASSERT(cursorTargetTableName != null);
0242:
0243:                        targetTableName = cursorTargetTableName;
0244:                    }
0245:                    // for positioned update, we need to verify that
0246:                    // the named table is the same as the cursor's target.
0247:                    else if (cursorTargetTableName != null) {
0248:                        // this match requires that the named table in the update
0249:                        // be the same as a correlation name in the cursor.
0250:                        if (!targetTableName.equals(cursorTargetTableName)) {
0251:                            throw StandardException.newException(
0252:                                    SQLState.LANG_CURSOR_UPDATE_MISMATCH,
0253:                                    targetTableName, currentOfNode
0254:                                            .getCursorName());
0255:                        }
0256:                    }
0257:                }
0258:
0259:                // because we verified that the tables match
0260:                // and we already bound the cursor or the select,
0261:                // the table descriptor should always be found.
0262:                verifyTargetTable();
0263:
0264:                /* OVERVIEW - We generate a new ResultColumn, CurrentRowLocation(), and
0265:                 * prepend it to the beginning of the source ResultColumnList.  This
0266:                 * will tell us which row(s) to update at execution time.  However,
0267:                 * we must defer prepending this generated column until the other
0268:                 * ResultColumns are bound since there will be no ColumnDescriptor
0269:                 * for the generated column.  Thus, the sequence of actions is:
0270:                 *
0271:                 *		o  Bind existing ResultColumnList (columns in SET clause)
0272:                 *		o  If this is a positioned update with a FOR UPDATE OF list,
0273:                 *		   then verify that all of the target columns are in the
0274:                 *		   FOR UPDATE OF list.
0275:                 *		o  Get the list of indexes that need to be updated.
0276:                 *		o  Create a ResultColumnList of all the columns in the target
0277:                 *		   table - this represents the old row.
0278:                 *		o  If we don't know which columns are being updated, 
0279:                 *		   expand the original ResultColumnList to include all the
0280:                 *		   columns in the target table, and sort it to be in the
0281:                 *		   order of the columns in the target table.  This represents
0282:                 *		   the new row.  Append it to the ResultColumnList representing
0283:                 *		   the old row.
0284:                 *		o  Construct the changedColumnIds array sorted by column position.
0285:                 *		o  Generate the read column bit map and append any columns
0286:                 *		   needed for index maint, etc.
0287:                 *		o  Generate a new ResultColumn for CurrentRowLocation() and 
0288:                 *		   mark it as a generated column.
0289:                 *		o  Append the new ResultColumn to the ResultColumnList
0290:                 *		   (This must be done before binding the expressions, so
0291:                 *		   that the proper type info gets propagated to the new 
0292:                 *		   ResultColumn.)
0293:                 *		o  Bind the expressions.
0294:                 *		o  Bind the generated ResultColumn.
0295:                 */
0296:
0297:                /* Verify that all underlying ResultSets reclaimed their FromList */
0298:                if (SanityManager.DEBUG) {
0299:                    SanityManager.ASSERT(fromList.size() == 0,
0300:                            "fromList.size() is expected to be 0, not "
0301:                                    + fromList.size()
0302:                                    + " on return from RS.bindExpressions()");
0303:                }
0304:
0305:                /*
0306:                 ** The current result column list is the one supplied by the user.
0307:                 ** Mark these columns as "updated", so we can tell later which
0308:                 ** columns are really being updated, and which have been added
0309:                 ** but are not really being updated.
0310:                 */
0311:                resultSet.getResultColumns().markUpdated();
0312:
0313:                /* Prepend CurrentRowLocation() to the select's result column list. */
0314:                if (SanityManager.DEBUG)
0315:                    SanityManager
0316:                            .ASSERT((resultSet.resultColumns != null),
0317:                                    "resultColumns is expected not to be null at bind time");
0318:
0319:                /*
0320:                 ** Get the result FromTable, which should be the only table in the
0321:                 ** from list.
0322:                 */
0323:                resultFromList = resultSet.getFromList();
0324:                if (SanityManager.DEBUG)
0325:                    SanityManager
0326:                            .ASSERT(resultFromList.size() == 1,
0327:                                    "More than one table in result from list in an update.");
0328:
0329:                /* Normalize the SET clause's result column list for synonym */
0330:                if (synonymTableName != null)
0331:                    normalizeSynonymColumns(resultSet.resultColumns,
0332:                            targetTable);
0333:
0334:                /* Bind the original result columns by column name */
0335:                normalizeCorrelatedColumns(resultSet.resultColumns, targetTable);
0336:
0337:                getCompilerContext().pushCurrentPrivType(getPrivType()); // Update privilege
0338:                resultSet.bindResultColumns(targetTableDescriptor, targetVTI,
0339:                        resultSet.resultColumns, this , fromList);
0340:                getCompilerContext().popCurrentPrivType();
0341:
0342:                LanguageConnectionContext lcc = getLanguageConnectionContext();
0343:                if (lcc.getAutoincrementUpdate() == false)
0344:                    resultSet.getResultColumns().checkAutoincrement(null);
0345:
0346:                /*
0347:                 ** Mark the columns in this UpdateNode's result column list as
0348:                 ** updateable in the ResultColumnList of the table being updated.
0349:                 ** only do this for FromBaseTables - if the result table is a
0350:                 ** CurrentOfNode, it already knows what columns in its cursor
0351:                 ** are updateable.
0352:                 */
0353:                boolean allColumns = false;
0354:                if (targetTable instanceof  FromBaseTable) {
0355:                    ((FromBaseTable) targetTable).markUpdated(resultSet
0356:                            .getResultColumns());
0357:                } else if (targetTable instanceof  FromVTI) {
0358:                    resultColumnList = resultSet.getResultColumns();
0359:                } else {
0360:                    /*
0361:                     ** Positioned update: WHERE CURRENT OF
0362:                     */
0363:                    if (SanityManager.DEBUG) {
0364:                        SanityManager.ASSERT(currentOfNode != null,
0365:                                "currentOfNode is null");
0366:                    }
0367:
0368:                    ExecPreparedStatement cursorStmt = currentOfNode
0369:                            .getCursorStatement();
0370:                    String[] ucl = cursorStmt.getUpdateColumns();
0371:
0372:                    /*
0373:                     ** If there is no update column list, we need to build
0374:                     ** out the result column list to have all columns.
0375:                     */
0376:                    if (ucl == null || (ucl.length == 0)) {
0377:                        /*
0378:                         ** Get the resultColumnList representing ALL of the columns in the 
0379:                         ** base table.  This is the "before" portion of the result row.
0380:                         */
0381:                        getResultColumnList();
0382:
0383:                        /*
0384:                         ** Add the "after" portion of the result row.  This is the update
0385:                         ** list augmented to include every column in the target table.
0386:                         ** Those columns that are not being updated are set to themselves.
0387:                         ** The expanded list will be in the order of the columns in the base
0388:                         ** table.
0389:                         */
0390:                        afterColumns = resultSet.getResultColumns()
0391:                                .expandToAll(targetTableDescriptor,
0392:                                        targetTable.getTableName());
0393:
0394:                        /*
0395:                         ** Need to get all indexes here since we aren't calling
0396:                         ** getReadMap().
0397:                         */
0398:                        getAffectedIndexes(targetTableDescriptor,
0399:                                (ResultColumnList) null,
0400:                                (FormatableBitSet) null);
0401:                        allColumns = true;
0402:                    } else {
0403:                        /* Check the updatability */
0404:                        resultSet.getResultColumns().checkColumnUpdateability(
0405:                                ucl, currentOfNode.getCursorName());
0406:                    }
0407:                }
0408:
0409:                changedColumnIds = getChangedColumnIds(resultSet
0410:                        .getResultColumns());
0411:
0412:                /*
0413:                 ** We need to add in all the columns that are needed
0414:                 ** by the constraints on this table.  
0415:                 */
0416:                if (!allColumns && targetVTI == null) {
0417:                    getCompilerContext().pushCurrentPrivType(
0418:                            Authorizer.NULL_PRIV);
0419:                    try {
0420:                        readColsBitSet = new FormatableBitSet();
0421:                        FromBaseTable fbt = getResultColumnList(resultSet
0422:                                .getResultColumns());
0423:                        afterColumns = resultSet.getResultColumns()
0424:                                .copyListAndObjects();
0425:
0426:                        readColsBitSet = getReadMap(dataDictionary,
0427:                                targetTableDescriptor, afterColumns);
0428:
0429:                        afterColumns = fbt.addColsToList(afterColumns,
0430:                                readColsBitSet);
0431:                        resultColumnList = fbt.addColsToList(resultColumnList,
0432:                                readColsBitSet);
0433:
0434:                        /*
0435:                         ** If all bits are set, then behave as if we chose all
0436:                         ** in the first place
0437:                         */
0438:                        int i = 1;
0439:                        int size = targetTableDescriptor.getMaxColumnID();
0440:                        for (; i <= size; i++) {
0441:                            if (!readColsBitSet.get(i)) {
0442:                                break;
0443:                            }
0444:                        }
0445:
0446:                        if (i > size) {
0447:                            readColsBitSet = null;
0448:                            allColumns = true;
0449:                        }
0450:                    } finally {
0451:                        getCompilerContext().popCurrentPrivType();
0452:                    }
0453:                }
0454:
0455:                if (targetVTI == null) {
0456:                    /*
0457:                     ** Construct an empty heap row for use in our constant action.
0458:                     */
0459:                    emptyHeapRow = targetTableDescriptor
0460:                            .getEmptyExecRow(getContextManager());
0461:
0462:                    /* Append the list of "after" columns to the list of "before" columns,
0463:                     * preserving the afterColumns list.  (Necessary for binding
0464:                     * check constraints.)
0465:                     */
0466:                    resultColumnList.appendResultColumns(afterColumns, false);
0467:
0468:                    /* Generate the RowLocation column */
0469:                    rowLocationNode = (CurrentRowLocationNode) getNodeFactory()
0470:                            .getNode(C_NodeTypes.CURRENT_ROW_LOCATION_NODE,
0471:                                    getContextManager());
0472:                } else {
0473:                    rowLocationNode = (NumericConstantNode) getNodeFactory()
0474:                            .getNode(C_NodeTypes.INT_CONSTANT_NODE,
0475:                                    ReuseFactory.getInteger(0),
0476:                                    getContextManager());
0477:                }
0478:
0479:                rowLocationColumn = (ResultColumn) getNodeFactory().getNode(
0480:                        C_NodeTypes.RESULT_COLUMN, COLUMNNAME, rowLocationNode,
0481:                        getContextManager());
0482:                rowLocationColumn.markGenerated();
0483:
0484:                /* Append to the ResultColumnList */
0485:                resultColumnList.addResultColumn(rowLocationColumn);
0486:
0487:                /*
0488:                 * The last thing that we do to the generated RCL is to clear
0489:                 * the table name out from each RC. See comment on 
0490:                 * checkTableNameAndScrubResultColumns().
0491:                 */
0492:                checkTableNameAndScrubResultColumns(resultColumnList);
0493:
0494:                /* Set the new result column list in the result set */
0495:                resultSet.setResultColumns(resultColumnList);
0496:
0497:                /* Bind the expressions */
0498:                getCompilerContext().pushCurrentPrivType(getPrivType()); // Update privilege
0499:                super .bindExpressions();
0500:                getCompilerContext().popCurrentPrivType();
0501:
0502:                /* Bind untyped nulls directly under the result columns */
0503:                resultSet.getResultColumns().bindUntypedNullsToResultColumns(
0504:                        resultColumnList);
0505:
0506:                if (null != rowLocationColumn) {
0507:                    /* Bind the new ResultColumn */
0508:                    rowLocationColumn.bindResultColumnToExpression();
0509:                }
0510:
0511:                resultColumnList.checkStorableExpressions();
0512:
0513:                /* Insert a NormalizeResultSetNode above the source if the source
0514:                 * and target column types and lengths do not match.
0515:                 */
0516:                if (!resultColumnList.columnTypesAndLengthsMatch()) {
0517:                    resultSet = resultSet.genNormalizeResultSetNode(resultSet,
0518:                            true);
0519:                    resultColumnList.copyTypesAndLengthsToSource(resultSet
0520:                            .getResultColumns());
0521:
0522:                    if (hasCheckConstraints(dataDictionary,
0523:                            targetTableDescriptor)) {
0524:                        /* Get and bind all check constraints on the columns
0525:                         * being updated.  We want to bind the check constraints against
0526:                         * the after columns.  We need to bind against the portion of the
0527:                         * resultColumns in the new NormalizeResultSet that point to 
0528:                         * afterColumns.  Create an RCL composed of just those RCs in
0529:                         * order to bind the check constraints.
0530:                         */
0531:                        int afterColumnsSize = afterColumns.size();
0532:                        afterColumns = (ResultColumnList) getNodeFactory()
0533:                                .getNode(C_NodeTypes.RESULT_COLUMN_LIST,
0534:                                        getContextManager());
0535:                        ResultColumnList normalizedRCs = resultSet
0536:                                .getResultColumns();
0537:                        for (int index = 0; index < afterColumnsSize; index++) {
0538:                            afterColumns.addElement(normalizedRCs
0539:                                    .elementAt(index + afterColumnsSize));
0540:                        }
0541:                    }
0542:                }
0543:
0544:                if (null != targetVTI) {
0545:                    deferred = VTIDeferModPolicy.deferIt(
0546:                            DeferModification.UPDATE_STATEMENT, targetVTI,
0547:                            resultColumnList.getColumnNames(), sel
0548:                                    .getWhereClause());
0549:                } else // not VTI
0550:                {
0551:                    /* we always include triggers in core language */
0552:                    boolean hasTriggers = (getAllRelevantTriggers(
0553:                            dataDictionary, targetTableDescriptor,
0554:                            changedColumnIds, true).size() > 0);
0555:
0556:                    /* Get and bind all constraints on the columns being updated */
0557:                    checkConstraints = bindConstraints(dataDictionary,
0558:                            getNodeFactory(), targetTableDescriptor, null,
0559:                            hasTriggers ? resultColumnList : afterColumns,
0560:                            changedColumnIds, readColsBitSet, false, true); /* we always include triggers in core language */
0561:
0562:                    /* If the target table is also a source table, then
0563:                     * the update will have to be in deferred mode
0564:                     * For updates, this means that the target table appears in a
0565:                     * subquery.  Also, self referencing foreign keys are
0566:                     * deferred.  And triggers cause an update to be deferred.
0567:                     */
0568:                    if (resultSet.subqueryReferencesTarget(
0569:                            targetTableDescriptor.getName(), true)
0570:                            || requiresDeferredProcessing()) {
0571:                        deferred = true;
0572:                    }
0573:                }
0574:
0575:                getCompilerContext().popCurrentPrivType();
0576:
0577:                return this ;
0578:            } // end of bind()
0579:
0580:            int getPrivType() {
0581:                return Authorizer.UPDATE_PRIV;
0582:            }
0583:
0584:            /**
0585:             * Return true if the node references SESSION schema tables (temporary or permanent)
0586:             *
0587:             * @return	true if references SESSION schema tables, else false
0588:             *
0589:             * @exception StandardException		Thrown on error
0590:             */
0591:            public boolean referencesSessionSchema() throws StandardException {
0592:                //If this node references a SESSION schema table, then return true. 
0593:                return (resultSet.referencesSessionSchema());
0594:
0595:            }
0596:
0597:            /**
0598:             * Compile constants that Execution will use
0599:             *
0600:             * @exception StandardException		Thrown on failure
0601:             */
0602:            public ConstantAction makeConstantAction() throws StandardException {
0603:                /*
0604:                 ** Updates are also deferred if they update a column in the index
0605:                 ** used to scan the table being updated.
0606:                 */
0607:                if (!deferred) {
0608:                    ConglomerateDescriptor updateCD = targetTable
0609:                            .getTrulyTheBestAccessPath()
0610:                            .getConglomerateDescriptor();
0611:
0612:                    if (updateCD != null && updateCD.isIndex()) {
0613:                        int[] baseColumns = updateCD.getIndexDescriptor()
0614:                                .baseColumnPositions();
0615:
0616:                        if (resultSet.getResultColumns().updateOverlaps(
0617:                                baseColumns)) {
0618:                            deferred = true;
0619:                        }
0620:                    }
0621:                }
0622:
0623:                if (null == targetTableDescriptor) {
0624:                    /* Return constant action for VTI
0625:                     * NOTE: ConstantAction responsible for preserving instantiated
0626:                     * VTIs for in-memory queries and for only preserving VTIs
0627:                     * that implement Serializable for SPSs.
0628:                     */
0629:                    return getGenericConstantActionFactory()
0630:                            .getUpdatableVTIConstantAction(
0631:                                    DeferModification.UPDATE_STATEMENT,
0632:                                    deferred, changedColumnIds);
0633:                }
0634:
0635:                int lockMode = resultSet.updateTargetLockMode();
0636:                long heapConglomId = targetTableDescriptor
0637:                        .getHeapConglomerateId();
0638:                TransactionController tc = getLanguageConnectionContext()
0639:                        .getTransactionCompile();
0640:                StaticCompiledOpenConglomInfo[] indexSCOCIs = new StaticCompiledOpenConglomInfo[indexConglomerateNumbers.length];
0641:
0642:                for (int index = 0; index < indexSCOCIs.length; index++) {
0643:                    indexSCOCIs[index] = tc
0644:                            .getStaticCompiledConglomInfo(indexConglomerateNumbers[index]);
0645:                }
0646:
0647:                /*
0648:                 ** Do table locking if the table's lock granularity is
0649:                 ** set to table.
0650:                 */
0651:                if (targetTableDescriptor.getLockGranularity() == TableDescriptor.TABLE_LOCK_GRANULARITY) {
0652:                    lockMode = TransactionController.MODE_TABLE;
0653:                }
0654:
0655:                return getGenericConstantActionFactory()
0656:                        .getUpdateConstantAction(
0657:                                heapConglomId,
0658:                                targetTableDescriptor.getTableType(),
0659:                                tc.getStaticCompiledConglomInfo(heapConglomId),
0660:                                indicesToMaintain,
0661:                                indexConglomerateNumbers,
0662:                                indexSCOCIs,
0663:                                indexNames,
0664:                                emptyHeapRow,
0665:                                deferred,
0666:                                targetTableDescriptor.getUUID(),
0667:                                lockMode,
0668:                                false,
0669:                                changedColumnIds,
0670:                                null,
0671:                                null,
0672:                                getFKInfo(),
0673:                                getTriggerInfo(),
0674:                                (readColsBitSet == null) ? (FormatableBitSet) null
0675:                                        : new FormatableBitSet(readColsBitSet),
0676:                                getReadColMap(targetTableDescriptor
0677:                                        .getNumberOfColumns(), readColsBitSet),
0678:                                resultColumnList
0679:                                        .getStreamStorableColIds(targetTableDescriptor
0680:                                                .getNumberOfColumns()),
0681:                                (readColsBitSet == null) ? targetTableDescriptor
0682:                                        .getNumberOfColumns()
0683:                                        : readColsBitSet.getNumBitsSet(),
0684:                                positionedUpdate, resultSet.isOneRowResultSet());
0685:            }
0686:
0687:            /**
0688:             * Updates are deferred if they update a column in the index
0689:             * used to scan the table being updated.
0690:             */
0691:            protected void setDeferredForUpdateOfIndexColumn() {
0692:                /* Don't bother checking if we're already deferred */
0693:                if (!deferred) {
0694:                    /* Get the conglomerate descriptor for the target table */
0695:                    ConglomerateDescriptor updateCD = targetTable
0696:                            .getTrulyTheBestAccessPath()
0697:                            .getConglomerateDescriptor();
0698:
0699:                    /* If it an index? */
0700:                    if (updateCD != null && updateCD.isIndex()) {
0701:                        int[] baseColumns = updateCD.getIndexDescriptor()
0702:                                .baseColumnPositions();
0703:
0704:                        /* Are any of the index columns updated? */
0705:                        if (resultSet.getResultColumns().updateOverlaps(
0706:                                baseColumns)) {
0707:                            deferred = true;
0708:                        }
0709:                    }
0710:                }
0711:            }
0712:
0713:            /**
0714:             * Code generation for update.
0715:             * The generated code will contain:
0716:             *		o  A static member for the (xxx)ResultSet with the RowLocations	and
0717:             *		   new update values
0718:             *		o  The static member will be assigned the appropriate ResultSet within
0719:             *		   the nested calls to get the ResultSets.  (The appropriate cast to the
0720:             *		   (xxx)ResultSet will be generated.)
0721:             *		o  The CurrentRowLocation() in SelectNode's select list will generate
0722:             *		   a new method for returning the RowLocation as well as a call to
0723:             *		   that method when generating the (xxx)ResultSet.
0724:             *
0725:             * @param acb	The ActivationClassBuilder for the class being built
0726:             * @param mb	The method for the execute() method to be built
0727:             *
0728:             *
0729:             * @exception StandardException		Thrown on error
0730:             */
0731:            public void generate(ActivationClassBuilder acb, MethodBuilder mb)
0732:                    throws StandardException {
0733:                //If the DML is on the temporary table, generate the code to mark temporary table as modified in the current UOW
0734:                generateCodeForTemporaryTable(acb, mb);
0735:
0736:                /* generate the parameters */
0737:                if (!isDependentTable)
0738:                    generateParameterValueSet(acb);
0739:
0740:                /* Create the static declaration for the scan ResultSet which generates the
0741:                 * RowLocations to be updated
0742:                 * RESOLVE - Need to deal with the type of the static member.
0743:                 */
0744:                acb.newFieldDeclaration(Modifier.PRIVATE,
0745:                        ClassName.CursorResultSet, acb
0746:                                .newRowLocationScanResultSetName());
0747:
0748:                /*
0749:                 ** Generate the update result set, giving it either the original
0750:                 ** source or the normalize result set, the constant action.
0751:                 */
0752:
0753:                acb.pushGetResultSetFactoryExpression(mb);
0754:                resultSet.generate(acb, mb); // arg 1
0755:
0756:                if (null != targetVTI) {
0757:                    targetVTI
0758:                            .assignCostEstimate(resultSet.getNewCostEstimate());
0759:                    mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
0760:                            "getUpdateVTIResultSet", ClassName.ResultSet, 1);
0761:                } else {
0762:                    // generate code to evaluate CHECK CONSTRAINTS
0763:                    generateCheckConstraints(checkConstraints, acb, mb); // arg 2
0764:
0765:                    if (isDependentTable) {
0766:                        mb.push(acb.addItem(makeConstantAction()));
0767:                        mb.push(acb.addItem(makeResultDescription()));
0768:                        mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
0769:                                "getDeleteCascadeUpdateResultSet",
0770:                                ClassName.ResultSet, 4);
0771:                    } else {
0772:                        mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
0773:                                "getUpdateResultSet", ClassName.ResultSet, 2);
0774:                    }
0775:                }
0776:            }
0777:
0778:            /**
0779:             * Return the type of statement, something from
0780:             * StatementType.
0781:             *
0782:             * @return the type of statement
0783:             */
0784:            protected final int getStatementType() {
0785:                return StatementType.UPDATE;
0786:            }
0787:
0788:            /**
0789:             * Gets the map of all columns which must be read out of the base table.
0790:             * These are the columns needed to<UL>:
0791:             *		<LI>maintain indices</LI>
0792:             *		<LI>maintain foreign keys</LI>
0793:             *		<LI>support Replication's Delta Optimization</LI></UL>
0794:             * <p>
0795:             * The returned map is a FormatableBitSet with 1 bit for each column in the
0796:             * table plus an extra, unsued 0-bit. If a 1-based column id must
0797:             * be read from the base table, then the corresponding 1-based bit
0798:             * is turned ON in the returned FormatableBitSet.
0799:             * <p> 
0800:             * <B>NOTE</B>: this method is not expected to be called when
0801:             * all columns are being updated (i.e. updateColumnList is null).
0802:             *
0803:             * @param dd				the data dictionary to look in
0804:             * @param baseTable		the base table descriptor
0805:             * @param updateColumnList the rcl for the update. CANNOT BE NULL
0806:             *
0807:             * @return a FormatableBitSet of columns to be read out of the base table
0808:             *
0809:             * @exception StandardException		Thrown on error
0810:             */
0811:            public FormatableBitSet getReadMap(DataDictionary dd,
0812:                    TableDescriptor baseTable, ResultColumnList updateColumnList)
0813:                    throws StandardException {
0814:                boolean[] needsDeferredProcessing = new boolean[1];
0815:                needsDeferredProcessing[0] = requiresDeferredProcessing();
0816:
0817:                Vector conglomVector = new Vector();
0818:                relevantCdl = new ConstraintDescriptorList();
0819:                relevantTriggers = new GenericDescriptorList();
0820:
0821:                FormatableBitSet columnMap = UpdateNode.getUpdateReadMap(
0822:                        baseTable, updateColumnList, conglomVector,
0823:                        relevantCdl, relevantTriggers, needsDeferredProcessing);
0824:
0825:                markAffectedIndexes(conglomVector);
0826:
0827:                adjustDeferredFlag(needsDeferredProcessing[0]);
0828:
0829:                return columnMap;
0830:            }
0831:
0832:            /**
0833:             * Construct the changedColumnIds array. Note we sort its entries by
0834:             * columnId.
0835:             */
0836:            private int[] getChangedColumnIds(ResultColumnList rcl) {
0837:                if (rcl == null) {
0838:                    return (int[]) null;
0839:                } else {
0840:                    return rcl.sortMe();
0841:                }
0842:            }
0843:
0844:            /**
0845:             *	Builds a bitmap of all columns which should be read from the
0846:             *	Store in order to satisfy an UPDATE statement.
0847:             *
0848:             *	Is passed a list of updated columns. Does the following:
0849:             *
0850:             *	1)	finds all indices which overlap the updated columns
0851:             *	2)	adds the index columns to a bitmap of affected columns
0852:             *	3)	adds the index descriptors to a list of conglomerate
0853:             *		descriptors.
0854:             *	4)	finds all constraints which overlap the updated columns
0855:             *		and adds the constrained columns to the bitmap
0856:             *	5)	finds all triggers which overlap the updated columns.
0857:             *	6)	if there are any triggers, marks all columns in the bitmap
0858:             *	7)	adds the triggers to an evolving list of triggers
0859:             *
0860:             *	@param	updateColumnList	a list of updated columns
0861:             *	@param	conglomVector		OUT: vector of affected indices
0862:             *	@param	relevantConstraints	IN/OUT. Empty list is passed in. We hang constraints on it as we go.
0863:             *	@param	relevantTriggers	IN/OUT. Passed in as an empty list. Filled in as we go.
0864:             *	@param	needsDeferredProcessing	IN/OUT. true if the statement already needs
0865:             *									deferred processing. set while evaluating this
0866:             *									routine if a trigger or constraint requires
0867:             *									deferred processing
0868:             *
0869:             * @return a FormatableBitSet of columns to be read out of the base table
0870:             *
0871:             * @exception StandardException		Thrown on error
0872:             */
0873:            public static FormatableBitSet getUpdateReadMap(
0874:                    TableDescriptor baseTable,
0875:                    ResultColumnList updateColumnList, Vector conglomVector,
0876:                    ConstraintDescriptorList relevantConstraints,
0877:                    GenericDescriptorList relevantTriggers,
0878:                    boolean[] needsDeferredProcessing) throws StandardException {
0879:                if (SanityManager.DEBUG) {
0880:                    SanityManager.ASSERT(updateColumnList != null,
0881:                            "updateColumnList is null");
0882:                }
0883:
0884:                int columnCount = baseTable.getMaxColumnID();
0885:                FormatableBitSet columnMap = new FormatableBitSet(
0886:                        columnCount + 1);
0887:
0888:                /*
0889:                 ** Add all the changed columns.  We don't strictly
0890:                 ** need the before image of the changed column in all cases,
0891:                 ** but it makes life much easier since things are set
0892:                 ** up around the assumption that we have the before
0893:                 ** and after image of the column.
0894:                 */
0895:                int[] changedColumnIds = updateColumnList.sortMe();
0896:
0897:                for (int ix = 0; ix < changedColumnIds.length; ix++) {
0898:                    columnMap.set(changedColumnIds[ix]);
0899:                }
0900:
0901:                /* 
0902:                 ** Get a list of the indexes that need to be 
0903:                 ** updated.  ColumnMap contains all indexed
0904:                 ** columns where 1 or more columns in the index
0905:                 ** are going to be modified.
0906:                 */
0907:                DMLModStatementNode.getXAffectedIndexes(baseTable,
0908:                        updateColumnList, columnMap, conglomVector);
0909:
0910:                /* 
0911:                 ** Add all columns needed for constraints.  We don't
0912:                 ** need to bother with foreign key/primary key constraints
0913:                 ** because they are added as a side effect of adding
0914:                 ** their indexes above.
0915:                 */
0916:                baseTable.getAllRelevantConstraints(StatementType.UPDATE,
0917:                        false, changedColumnIds, needsDeferredProcessing,
0918:                        relevantConstraints);
0919:
0920:                int rclSize = relevantConstraints.size();
0921:                for (int index = 0; index < rclSize; index++) {
0922:                    ConstraintDescriptor cd = relevantConstraints
0923:                            .elementAt(index);
0924:                    if (cd.getConstraintType() != DataDictionary.CHECK_CONSTRAINT) {
0925:                        continue;
0926:                    }
0927:
0928:                    int[] refColumns = ((CheckConstraintDescriptor) cd)
0929:                            .getReferencedColumns();
0930:                    for (int i = 0; i < refColumns.length; i++) {
0931:                        columnMap.set(refColumns[i]);
0932:                    }
0933:                }
0934:
0935:                /*
0936:                 ** If we have any triggers, then get all the columns
0937:                 ** because we don't know what the user will ultimately
0938:                 ** reference.
0939:                 */
0940:
0941:                baseTable.getAllRelevantTriggers(StatementType.UPDATE,
0942:                        changedColumnIds, relevantTriggers);
0943:                if (relevantTriggers.size() > 0) {
0944:                    needsDeferredProcessing[0] = true;
0945:                }
0946:
0947:                if (relevantTriggers.size() > 0) {
0948:                    for (int i = 1; i <= columnCount; i++) {
0949:                        columnMap.set(i);
0950:                    }
0951:                }
0952:
0953:                return columnMap;
0954:            }
0955:
0956:            /*
0957:             * Force correlated column references in the SET clause to have the
0958:             * name of the base table. This dances around the problem alluded to
0959:             * in scrubResultColumn().
0960:             */
0961:            private void normalizeCorrelatedColumns(ResultColumnList rcl,
0962:                    FromTable fromTable) throws StandardException {
0963:                String correlationName = fromTable.getCorrelationName();
0964:
0965:                if (correlationName == null) {
0966:                    return;
0967:                }
0968:
0969:                TableName tableNameNode;
0970:
0971:                if (fromTable instanceof  CurrentOfNode) {
0972:                    tableNameNode = ((CurrentOfNode) fromTable)
0973:                            .getBaseCursorTargetTableName();
0974:                } else {
0975:                    tableNameNode = makeTableName(null, fromTable
0976:                            .getBaseTableName());
0977:                }
0978:
0979:                int count = rcl.size();
0980:
0981:                for (int i = 0; i < count; i++) {
0982:                    ResultColumn column = (ResultColumn) rcl.elementAt(i);
0983:                    ColumnReference reference = column.getReference();
0984:
0985:                    if ((reference != null)
0986:                            && correlationName.equals(reference.getTableName())) {
0987:                        reference.setTableNameNode(tableNameNode);
0988:                    }
0989:                }
0990:
0991:            }
0992:
0993:            /**
0994:             * Check table name and then clear it from the result set columns.
0995:             * 
0996:             * @exception StandardExcepion if invalid column/table is specified.
0997:             */
0998:            private void checkTableNameAndScrubResultColumns(
0999:                    ResultColumnList rcl) throws StandardException {
1000:                int columnCount = rcl.size();
1001:                int tableCount = ((SelectNode) resultSet).fromList.size();
1002:
1003:                for (int i = 0; i < columnCount; i++) {
1004:                    boolean foundMatchingTable = false;
1005:                    ResultColumn column = (ResultColumn) rcl.elementAt(i);
1006:
1007:                    if (column.getTableName() != null) {
1008:                        for (int j = 0; j < tableCount; j++) {
1009:                            FromTable fromTable = (FromTable) ((SelectNode) resultSet).fromList
1010:                                    .elementAt(j);
1011:                            final String tableName;
1012:                            if (fromTable instanceof  CurrentOfNode) {
1013:                                tableName = ((CurrentOfNode) fromTable)
1014:                                        .getBaseCursorTargetTableName()
1015:                                        .getTableName();
1016:                            } else {
1017:                                tableName = fromTable.getBaseTableName();
1018:                            }
1019:
1020:                            if (column.getTableName().equals(tableName)) {
1021:                                foundMatchingTable = true;
1022:                                break;
1023:                            }
1024:                        }
1025:
1026:                        if (!foundMatchingTable) {
1027:                            throw StandardException.newException(
1028:                                    SQLState.LANG_COLUMN_NOT_FOUND, column
1029:                                            .getTableName()
1030:                                            + "." + column.getName());
1031:                        }
1032:                    }
1033:
1034:                    /* The table name is
1035:                     * unnecessary for an update.  More importantly, though, it
1036:                     * creates a problem in the degenerate case with a positioned
1037:                     * update.  The user must specify the base table name for a
1038:                     * positioned update.  If a correlation name was specified for
1039:                     * the cursor, then a match for the ColumnReference would not
1040:                     * be found if we didn't null out the name.  (Aren't you
1041:                     * glad you asked?)
1042:                     */
1043:                    column.clearTableName();
1044:                }
1045:            }
1046:
1047:            /**
1048:             * Normalize synonym column references to have the name of the base table. 
1049:             *
1050:             * @param rcl	    The result column list of the target table
1051:             * @param fromTable The table name to set the column refs to
1052:             * 
1053:             * @exception StandardException		Thrown on error
1054:             */
1055:            private void normalizeSynonymColumns(ResultColumnList rcl,
1056:                    FromTable fromTable) throws StandardException {
1057:                if (fromTable.getCorrelationName() != null) {
1058:                    return;
1059:                }
1060:
1061:                TableName tableNameNode;
1062:                if (fromTable instanceof  CurrentOfNode) {
1063:                    tableNameNode = ((CurrentOfNode) fromTable)
1064:                            .getBaseCursorTargetTableName();
1065:                } else {
1066:                    tableNameNode = makeTableName(null, fromTable
1067:                            .getBaseTableName());
1068:                }
1069:
1070:                super .normalizeSynonymColumns(rcl, tableNameNode);
1071:            }
1072:
1073:        } // end of UpdateNode
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.