Source Code Cross Referenced for UpdateResultSet.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » sql » execute » 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.execute 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.sql.execute.UpdateResultSet
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.execute;
0023:
0024:        import org.apache.derby.iapi.services.loader.GeneratedMethod;
0025:        import org.apache.derby.iapi.services.monitor.Monitor;
0026:        import org.apache.derby.iapi.services.sanity.SanityManager;
0027:        import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
0028:        import org.apache.derby.iapi.services.stream.InfoStreams;
0029:        import org.apache.derby.iapi.services.io.StreamStorable;
0030:        import org.apache.derby.iapi.error.StandardException;
0031:        import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0032:        import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
0033:        import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0034:        import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
0035:        import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0036:        import org.apache.derby.iapi.types.BooleanDataValue;
0037:        import org.apache.derby.iapi.types.DataValueDescriptor;
0038:        import org.apache.derby.iapi.types.RowLocation;
0039:        import org.apache.derby.iapi.sql.execute.ConstantAction;
0040:        import org.apache.derby.iapi.sql.execute.CursorResultSet;
0041:        import org.apache.derby.iapi.sql.execute.ExecRow;
0042:        import org.apache.derby.iapi.sql.execute.ExecutionContext;
0043:        import org.apache.derby.iapi.sql.execute.RowChanger;
0044:        import org.apache.derby.iapi.sql.execute.NoPutResultSet;
0045:
0046:        import org.apache.derby.iapi.types.DataValueDescriptor;
0047:        import org.apache.derby.iapi.sql.Activation;
0048:        import org.apache.derby.iapi.sql.ResultDescription;
0049:        import org.apache.derby.iapi.sql.ResultSet;
0050:
0051:        import org.apache.derby.iapi.store.access.ConglomerateController;
0052:        import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
0053:        import org.apache.derby.iapi.store.access.ScanController;
0054:        import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
0055:        import org.apache.derby.iapi.store.access.TransactionController;
0056:
0057:        import org.apache.derby.iapi.reference.SQLState;
0058:
0059:        import org.apache.derby.iapi.db.TriggerExecutionContext;
0060:        import org.apache.derby.iapi.services.io.FormatableBitSet;
0061:        import java.util.Properties;
0062:        import java.util.Hashtable;
0063:
0064:        /**
0065:         * Update the rows from the specified
0066:         * base table. This will cause constraints to be checked
0067:         * and triggers to be executed based on the c's and t's
0068:         * compiled into the update plan.
0069:         *
0070:         * @author ames
0071:         */
0072:        class UpdateResultSet extends DMLWriteResultSet {
0073:            private TransactionController tc;
0074:            private ExecRow newBaseRow;
0075:            private ExecRow row;
0076:            private ExecRow deferredSparseRow;
0077:            UpdateConstantAction constants;
0078:
0079:            private ResultDescription resultDescription;
0080:            private NoPutResultSet source;
0081:            NoPutResultSet savedSource;
0082:            private RowChanger rowChanger;
0083:
0084:            protected ConglomerateController deferredBaseCC;
0085:
0086:            protected long[] deferredUniqueCIDs;
0087:            protected boolean[] deferredUniqueCreated;
0088:            protected ConglomerateController deferredUniqueCC[];
0089:            protected ScanController[] deferredUniqueScans;
0090:
0091:            private TemporaryRowHolderImpl deletedRowHolder;
0092:            private TemporaryRowHolderImpl insertedRowHolder;
0093:
0094:            // cached 
0095:            private RISetChecker riChecker;
0096:            private TriggerInfo triggerInfo;
0097:            private TriggerEventActivator triggerActivator;
0098:            private boolean updatingReferencedKey;
0099:            private boolean updatingForeignKey;
0100:            private int numOpens;
0101:            private long heapConglom;
0102:            private FKInfo[] fkInfoArray;
0103:            private FormatableBitSet baseRowReadList;
0104:            private GeneratedMethod checkGM;
0105:            private int resultWidth;
0106:            private int numberOfBaseColumns;
0107:            private ExecRow deferredTempRow;
0108:            private ExecRow deferredBaseRow;
0109:            private ExecRow oldDeletedRow;
0110:            private ResultDescription triggerResultDescription;
0111:
0112:            int lockMode;
0113:            boolean deferred;
0114:            boolean beforeUpdateCopyRequired = false;
0115:
0116:            /**
0117:             * Returns the description of the updated rows.
0118:             * REVISIT: Do we want this to return NULL instead?
0119:             */
0120:            public ResultDescription getResultDescription() {
0121:                return resultDescription;
0122:            }
0123:
0124:            /*
0125:             * class interface
0126:             *
0127:             */
0128:            /**
0129:             * @param source update rows come from source
0130:             * @param checkGM	Generated method for enforcing check constraints
0131:             * @exception StandardException thrown on error
0132:             */
0133:            UpdateResultSet(NoPutResultSet source, GeneratedMethod checkGM,
0134:                    Activation activation) throws StandardException {
0135:                this (source, checkGM, activation, activation
0136:                        .getConstantAction(), null);
0137:            }
0138:
0139:            /*
0140:             * class interface
0141:             *
0142:             */
0143:            /**
0144:             * @param source update rows come from source
0145:             * @param checkGM	Generated method for enforcing check constraints
0146:             * @param activation Activation
0147:             * @param constantActionItem  id of the update constant action saved objec
0148:             * @param rsdItem  id of the Result Description saved object
0149:             * @exception StandardException thrown on error
0150:             */
0151:            UpdateResultSet(NoPutResultSet source, GeneratedMethod checkGM,
0152:                    Activation activation, int constantActionItem, int rsdItem)
0153:                    throws StandardException {
0154:                this (source, checkGM, activation, ((ConstantAction) activation
0155:                        .getPreparedStatement().getSavedObject(
0156:                                constantActionItem)),
0157:                        (ResultDescription) activation.getPreparedStatement()
0158:                                .getSavedObject(rsdItem));
0159:
0160:                // In case of referential action update, we do a deferred updates
0161:                deferred = true;
0162:            }
0163:
0164:            /*
0165:             * class interface
0166:             *
0167:             */
0168:            /**
0169:             * @param source update rows come from source
0170:             * @param checkGM	Generated method for enforcing check constraints
0171:             * @exception StandardException thrown on error
0172:             */
0173:            UpdateResultSet(NoPutResultSet source, GeneratedMethod checkGM,
0174:                    Activation activation,
0175:                    ConstantAction passedInConstantAction,
0176:                    ResultDescription passedInRsd) throws StandardException {
0177:                super (activation, passedInConstantAction);
0178:
0179:                // Get the current transaction controller
0180:                tc = activation.getTransactionController();
0181:                this .source = source;
0182:                this .checkGM = checkGM;
0183:
0184:                constants = (UpdateConstantAction) constantAction;
0185:                fkInfoArray = constants.getFKInfo(lcc.getExecutionContext());
0186:                triggerInfo = constants.getTriggerInfo(lcc
0187:                        .getExecutionContext());
0188:
0189:                heapConglom = constants.conglomId;
0190:
0191:                baseRowReadList = constants.getBaseRowReadList();
0192:                if (passedInRsd == null)
0193:                    resultDescription = source.getResultDescription();
0194:                else
0195:                    resultDescription = passedInRsd;
0196:                /*
0197:                 ** We NEED a result description when we are going to
0198:                 ** to have to kick off a trigger.  In a replicated environment
0199:                 ** we don't get a result description when we are replaying
0200:                 ** source xacts on the target, which should never be the
0201:                 ** case for an UpdateResultSet.
0202:                 */
0203:                if (SanityManager.DEBUG) {
0204:                    if (resultDescription == null) {
0205:                        SanityManager
0206:                                .ASSERT(triggerInfo == null,
0207:                                        "triggers need a result description to pass to result sets given to users");
0208:                    }
0209:                }
0210:
0211:                if (fkInfoArray != null) {
0212:                    for (int i = 0; i < fkInfoArray.length; i++) {
0213:                        if (fkInfoArray[i].type == FKInfo.REFERENCED_KEY) {
0214:                            updatingReferencedKey = true;
0215:                            if (SanityManager.DEBUG) {
0216:                                SanityManager
0217:                                        .ASSERT(constants.deferred,
0218:                                                "updating referenced key but update not deferred, wuzzup?");
0219:                            }
0220:                        } else {
0221:                            updatingForeignKey = true;
0222:                        }
0223:                    }
0224:                }
0225:
0226:                /* Get the # of columns in the ResultSet */
0227:                resultWidth = resultDescription.getColumnCount();
0228:
0229:                /*
0230:                 ** Calculate the # of columns in the base table.  The result set
0231:                 ** contains the before columns, the after columns, and the RowLocation,
0232:                 ** so the number of base columns is half of the number of result set
0233:                 ** columns, after subtracting one for the row location column.
0234:                 */
0235:                numberOfBaseColumns = (resultWidth - 1) / 2;
0236:
0237:                /* Get the new base row */
0238:                newBaseRow = RowUtil.getEmptyValueRow(numberOfBaseColumns, lcc);
0239:
0240:                /* decode lock mode */
0241:                lockMode = decodeLockMode(lcc, constants.lockMode);
0242:                deferred = constants.deferred;
0243:
0244:                //update can be marked for deferred mode because the scan is being done
0245:                //using index. But it is not necesary  to keep the before copy
0246:                //of the row in the temporary row holder (deletedRowHolder) unless
0247:                //there are RI constraint or Triggers.(beetle:5301)
0248:                if (triggerInfo != null || fkInfoArray != null) {
0249:                    beforeUpdateCopyRequired = true;
0250:                }
0251:
0252:            }
0253:
0254:            /**
0255:            	@exception StandardException Standard Cloudscape error policy
0256:             */
0257:            public void open() throws StandardException {
0258:
0259:                setup();
0260:                collectAffectedRows();
0261:
0262:                /*
0263:                 ** If this is a deferred update, read the new rows and RowLocations
0264:                 ** from the temporary conglomerate and update the base table using
0265:                 ** the RowChanger.
0266:                 */
0267:                if (deferred) {
0268:
0269:                    runChecker(true); //check for only RESTRICT referential action rule violations
0270:                    fireBeforeTriggers();
0271:                    updateDeferredRows();
0272:                    /* Apply deferred inserts to unique indexes */
0273:                    rowChanger.finish();
0274:                    runChecker(false); //check for all  violations
0275:                    fireAfterTriggers();
0276:
0277:                } else {
0278:                    /* Apply deferred inserts to unique indexes */
0279:                    rowChanger.finish();
0280:                }
0281:
0282:                cleanUp();
0283:            }
0284:
0285:            /**
0286:            	@exception StandardException Standard Cloudscape error policy
0287:             */
0288:            void setup() throws StandardException {
0289:                boolean firstOpen = (rowChanger == null);
0290:
0291:                rowCount = 0;
0292:
0293:                /* Cache query plan text for source, before it gets blown away */
0294:                if (lcc.getRunTimeStatisticsMode()) {
0295:                    /* savedSource nulled after run time statistics generation */
0296:                    savedSource = source;
0297:                }
0298:
0299:                /* Get or re-use the row changer.
0300:                 * NOTE: We need to set ourself as the top result set
0301:                 * if this is not the 1st execution.  (Done in constructor
0302:                 * for 1st execution.)
0303:                 */
0304:                if (firstOpen) {
0305:                    rowChanger = lcc.getLanguageConnectionFactory()
0306:                            .getExecutionFactory().getRowChanger(heapConglom,
0307:                                    constants.heapSCOCI, heapDCOCI,
0308:                                    constants.irgs, constants.indexCIDS,
0309:                                    constants.indexSCOCIs, indexDCOCIs,
0310:                                    constants.numColumns, tc,
0311:                                    constants.changedColumnIds,
0312:                                    constants.getBaseRowReadList(),
0313:                                    constants.getBaseRowReadMap(),
0314:                                    constants.getStreamStorableHeapColIds(),
0315:                                    activation);
0316:                    rowChanger.setIndexNames(constants.indexNames);
0317:                } else {
0318:                    lcc.getStatementContext().setTopResultSet(this ,
0319:                            subqueryTrackingArray);
0320:                }
0321:
0322:                /* Open the RowChanger before the source ResultSet so that
0323:                 * the store will see the RowChanger's lock as a covering lock
0324:                 * if it is a table lock.
0325:                 */
0326:                rowChanger.open(lockMode);
0327:
0328:                if (numOpens++ == 0) {
0329:                    source.openCore();
0330:                } else {
0331:                    source.reopenCore();
0332:                }
0333:
0334:                /* The source does not know whether or not we are doing a
0335:                 * deferred mode update.  If we are, then we must clear the
0336:                 * index scan info from the activation so that the row changer
0337:                 * does not re-use that information (which won't be valid for
0338:                 * a deferred mode update).
0339:                 */
0340:                if (deferred) {
0341:                    activation.clearIndexScanInfo();
0342:                }
0343:
0344:                if (fkInfoArray != null) {
0345:                    if (riChecker == null) {
0346:                        riChecker = new RISetChecker(tc, fkInfoArray);
0347:                    } else {
0348:                        riChecker.reopen();
0349:                    }
0350:                }
0351:
0352:                if (deferred) {
0353:                    /* Allocate the temporary rows and get result description
0354:                     * if this is the 1st time that we are executing.
0355:                     */
0356:                    if (firstOpen) {
0357:                        deferredTempRow = RowUtil.getEmptyValueRow(
0358:                                numberOfBaseColumns + 1, lcc);
0359:                        oldDeletedRow = RowUtil.getEmptyValueRow(
0360:                                numberOfBaseColumns, lcc);
0361:                        triggerResultDescription = (resultDescription != null) ? resultDescription
0362:                                .truncateColumns(numberOfBaseColumns + 1)
0363:                                : null;
0364:                    }
0365:
0366:                    Properties properties = new Properties();
0367:
0368:                    // Get the properties on the heap
0369:                    rowChanger.getHeapConglomerateController()
0370:                            .getInternalTablePropertySet(properties);
0371:                    if (beforeUpdateCopyRequired) {
0372:                        deletedRowHolder = new TemporaryRowHolderImpl(
0373:                                activation, properties,
0374:                                triggerResultDescription);
0375:                    }
0376:                    insertedRowHolder = new TemporaryRowHolderImpl(activation,
0377:                            properties, triggerResultDescription);
0378:
0379:                    rowChanger.setRowHolder(insertedRowHolder);
0380:                }
0381:
0382:            }
0383:
0384:            /* Following 2 methods are for checking and make sure we don't have one un-objectified stream
0385:             * to be inserted into 2 temp table rows for deferred update.  Otherwise it would cause problem
0386:             * when writing to disk using the stream a second time.  In other cases we don't want to
0387:             * unnecessarily objectify the stream. beetle 4896.
0388:             */
0389:            private FormatableBitSet checkStreamCols() {
0390:                DataValueDescriptor[] cols = row.getRowArray();
0391:                FormatableBitSet streamCols = null;
0392:                for (int i = 0; i < numberOfBaseColumns; i++) {
0393:                    if (cols[i + numberOfBaseColumns] instanceof  StreamStorable) //check new values
0394:                    {
0395:                        if (streamCols == null)
0396:                            streamCols = new FormatableBitSet(
0397:                                    numberOfBaseColumns);
0398:                        streamCols.set(i);
0399:                    }
0400:                }
0401:                return streamCols;
0402:            }
0403:
0404:            private void objectifyStream(ExecRow tempRow,
0405:                    FormatableBitSet streamCols) throws StandardException {
0406:                DataValueDescriptor[] cols = tempRow.getRowArray();
0407:                for (int i = 0; i < numberOfBaseColumns; i++) {
0408:                    if (cols[i] != null && streamCols.get(i))
0409:                        ((StreamStorable) cols[i]).loadStream();
0410:                }
0411:            }
0412:
0413:            public boolean collectAffectedRows() throws StandardException {
0414:
0415:                boolean rowsFound = false;
0416:                row = getNextRowCore(source);
0417:                if (row != null)
0418:                    rowsFound = true;
0419:                else {
0420:                    activation.addWarning(StandardException
0421:                            .newWarning(SQLState.LANG_NO_ROW_FOUND));
0422:                }
0423:
0424:                //beetle 3865, update cursor use index.
0425:                TableScanResultSet tableScan = (TableScanResultSet) activation
0426:                        .getForUpdateIndexScan();
0427:                boolean notifyCursor = ((tableScan != null) && !tableScan.sourceDrained);
0428:                boolean checkStream = (deferred && rowsFound && !constants.singleRowSource);
0429:                FormatableBitSet streamCols = (checkStream ? checkStreamCols()
0430:                        : null);
0431:                checkStream = (streamCols != null);
0432:
0433:                while (row != null) {
0434:
0435:                    /* By convention, the last column in the result set for an
0436:                     * update contains a SQLRef containing the RowLocation of
0437:                     * the row to be updated.
0438:                     */
0439:
0440:                    /*
0441:                     ** If we're doing deferred update, write the new row and row
0442:                     ** location to the temporary conglomerate.  If we're not doing
0443:                     ** deferred update, update the permanent conglomerates now
0444:                     ** using the RowChanger.
0445:                     */
0446:                    if (deferred) {
0447:                        /*
0448:                         ** If we have a before trigger, we must evaluate the 
0449:                         ** check constraint after we have executed the trigger.
0450:                         ** Note that we have compiled checkGM accordingly (to
0451:                         ** handle the different row shape if we are evaluating
0452:                         ** against the input result set or a temporary row holder
0453:                         ** result set).
0454:                         */
0455:                        if (triggerInfo == null) {
0456:                            evaluateCheckConstraints(checkGM, activation);
0457:                        }
0458:
0459:                        /*
0460:                         ** We are going to only save off the updated
0461:                         ** columns and the RID.  For a trigger, all columns
0462:                         ** were marked as needed so we'll copy them all.
0463:                         */
0464:                        RowUtil.copyRefColumns(deferredTempRow, row,
0465:                                numberOfBaseColumns, numberOfBaseColumns + 1);
0466:                        if (checkStream)
0467:                            objectifyStream(deferredTempRow, streamCols);
0468:
0469:                        insertedRowHolder.insert(deferredTempRow);
0470:
0471:                        /*
0472:                         ** Grab a copy of the row to delete.  We are
0473:                         ** going to use this for deferred RI checks.
0474:                         */
0475:                        if (beforeUpdateCopyRequired) {
0476:                            RowUtil.copyRefColumns(oldDeletedRow, row,
0477:                                    numberOfBaseColumns);
0478:
0479:                            deletedRowHolder.insert(oldDeletedRow);
0480:                        }
0481:
0482:                        /*
0483:                         ** If we haven't already, lets get a template to
0484:                         ** use as a template for our rescan of the base table.
0485:                         ** Do this now while we have a real row to use
0486:                         ** as a copy.
0487:                         **
0488:                         ** There is one less column in the base row than
0489:                         ** there is in source row, because the base row
0490:                         ** doesn't contain the row location.
0491:                         */
0492:                        if (deferredBaseRow == null) {
0493:                            deferredBaseRow = RowUtil.getEmptyValueRow(
0494:                                    numberOfBaseColumns, lcc);
0495:
0496:                            RowUtil.copyCloneColumns(deferredBaseRow, row,
0497:                                    numberOfBaseColumns);
0498:
0499:                            /*
0500:                             ** While we're here, let's also create a sparse row for
0501:                             ** fetching from the store.
0502:                             */
0503:                            deferredSparseRow = makeDeferredSparseRow(
0504:                                    deferredBaseRow, baseRowReadList, lcc);
0505:                        }
0506:                    } else {
0507:                        evaluateCheckConstraints(checkGM, activation);
0508:
0509:                        /* Get the RowLocation to update 
0510:                         * NOTE - Column #s in the Row are 1 based.
0511:                         */
0512:                        RowLocation baseRowLocation = (RowLocation) (row
0513:                                .getColumn(resultWidth)).getObject();
0514:
0515:                        RowUtil.copyRefColumns(newBaseRow, row,
0516:                                numberOfBaseColumns, numberOfBaseColumns);
0517:
0518:                        if (riChecker != null) {
0519:                            /*
0520:                             ** Make sure all foreign keys in the new row
0521:                             ** are maintained.  Note that we don't bother 
0522:                             ** checking primary/unique keys that are referenced
0523:                             ** here.  The reason is that if we are updating
0524:                             ** a referenced key, we'll be updating in deferred
0525:                             ** mode, so we wont get here.
0526:                             */
0527:                            riChecker.doFKCheck(newBaseRow);
0528:                        }
0529:
0530:                        source.updateRow(newBaseRow);
0531:                        rowChanger.updateRow(row, newBaseRow, baseRowLocation);
0532:
0533:                        //beetle 3865, update cursor use index.
0534:                        if (notifyCursor)
0535:                            notifyForUpdateCursor(row.getRowArray(), newBaseRow
0536:                                    .getRowArray(), baseRowLocation, tableScan);
0537:                    }
0538:
0539:                    rowCount++;
0540:
0541:                    // No need to do a next on a single row source
0542:                    if (constants.singleRowSource) {
0543:                        row = null;
0544:                    } else {
0545:                        row = getNextRowCore(source);
0546:                    }
0547:                }
0548:
0549:                return rowsFound;
0550:            }
0551:
0552:            /* beetle 3865, updateable cursor use index. If the row we are updating has new value that
0553:             * falls into the direction of the index scan of the cursor, we save this rid into a hash table
0554:             * (for fast search), so that when the cursor hits it again, it knows to skip it.  When we get
0555:             * to a point that the hash table is full, we scan forward the cursor until one of two things
0556:             * happen: (1) we hit a record whose rid is in the hash table (we went through it already, so
0557:             * skip it), we remove it from hash table, so that we can continue to use hash table. OR, (2) the scan
0558:             * forward hit the end.  If (2) happens, we can de-reference the hash table to make it available
0559:             * for garbage collection.  We save the future row id's in a virtual mem heap.  In any case,
0560:             * next read will use a row id that we saved.
0561:             */
0562:            private void notifyForUpdateCursor(DataValueDescriptor[] row,
0563:                    DataValueDescriptor[] newBaseRow, RowLocation rl,
0564:                    TableScanResultSet tableScan) throws StandardException {
0565:                int[] indexCols = tableScan.indexCols;
0566:                int[] changedCols = constants.changedColumnIds;
0567:                boolean placedForward = false, ascending, decided = false, overlap = false;
0568:                int basePos, k;
0569:                /* first of all, we see if there's overlap between changed column ids and index key
0570:                 * columns.  If so, we see if the new update value falls into the future range of the
0571:                 * index scan, if so, we need to save it in hash table.
0572:                 */
0573:                for (int i = 0; i < indexCols.length; i++) {
0574:                    basePos = indexCols[i];
0575:                    if (basePos > 0)
0576:                        ascending = true;
0577:                    else {
0578:                        ascending = false;
0579:                        basePos = -basePos;
0580:                    }
0581:                    for (int j = 0; j < changedCols.length; j++) {
0582:                        if (basePos == changedCols[j]) {
0583:                            decided = true; //we pretty much decided if new row falls in front
0584:                            //of the cursor or behind
0585:                            /* the row and newBaseRow we get are compact base row that only have
0586:                             * referenced columns.  Our "basePos" is index in sparse heap row, so
0587:                             * we need the BaseRowReadMap to map into the compact row.
0588:                             */
0589:                            int[] map = constants.getBaseRowReadMap();
0590:                            if (map == null)
0591:                                k = basePos - 1;
0592:                            else
0593:                                k = map[basePos - 1];
0594:
0595:                            DataValueDescriptor key;
0596:                            /* We need to compare with saved most-forward cursor scan key if we
0597:                             * are reading records from the saved RowLocation temp table (instead
0598:                             * of the old column value) because we only care if new update value
0599:                             * jumps forward the most-forward scan key.
0600:                             */
0601:                            if (tableScan.compareToLastKey)
0602:                                key = tableScan.lastCursorKey.getColumn(i + 1);
0603:                            else
0604:                                key = row[k];
0605:
0606:                            /* Starting from the first index key column forward, we see if the direction
0607:                             * of the update change is consistent with the direction of index scan.
0608:                             * If so, we save it in hash table.
0609:                             */
0610:                            if ((ascending && key.greaterThan(newBaseRow[k],
0611:                                    key).equals(true))
0612:                                    || (!ascending && key.lessThan(
0613:                                            newBaseRow[k], key).equals(true)))
0614:                                placedForward = true;
0615:                            else if (key.equals(newBaseRow[k], key)
0616:                                    .equals(true)) {
0617:                                decided = false;
0618:                                overlap = true;
0619:                            }
0620:                            break;
0621:                        }
0622:                    }
0623:                    if (decided) // already decided if new row falls in front or behind
0624:                        break;
0625:                }
0626:                /* If index row gets updated but key value didn't actually change, we still
0627:                 * put it in hash table because it can either fall in front or behind.  This
0628:                 * can happen if the update explicitly sets a value, but same as old.
0629:                 */
0630:                if (overlap && !decided)
0631:                    placedForward = true;
0632:
0633:                if (placedForward) // add it to hash table
0634:                {
0635:                    /* determining initial capacity of hash table from a few factors:
0636:                     * (1) user specified MAX_MEMORY_PER_TABLE property, (2) min value 100
0637:                     * (3) optimizer estimated row count.  We want to avoid re-hashing if
0638:                     * possible, for performance reason, yet don't waste space.  If initial
0639:                     * capacity is greater than max size divided by load factor, no rehash
0640:                     * is ever needed.
0641:                     */
0642:                    int maxCapacity = lcc.getOptimizerFactory()
0643:                            .getMaxMemoryPerTable() / 16;
0644:                    if (maxCapacity < 100)
0645:                        maxCapacity = 100;
0646:
0647:                    if (tableScan.past2FutureTbl == null) {
0648:                        double rowCount = tableScan.getEstimatedRowCount();
0649:                        int initCapacity = 32 * 1024;
0650:                        if (rowCount > 0.0) {
0651:                            rowCount = rowCount / 0.75 + 1.0; // load factor
0652:                            if (rowCount < initCapacity)
0653:                                initCapacity = (int) rowCount;
0654:                        }
0655:                        if (maxCapacity < initCapacity)
0656:                            initCapacity = maxCapacity;
0657:
0658:                        tableScan.past2FutureTbl = new Hashtable(initCapacity);
0659:                    }
0660:
0661:                    Hashtable past2FutureTbl = tableScan.past2FutureTbl;
0662:                    /* If hash table is not full, we add it in.  The key of the hash entry
0663:                     * is the string value of the RowLocation.  If the hash table is full,
0664:                     * as the comments above this function say, we scan forward.
0665:                     *
0666:                     * Need to save a clone because when we get cached currentRow, "rl" shares the
0667:                     * same reference, so is changed at the same time.
0668:                     */
0669:                    RowLocation updatedRL = (RowLocation) rl.getClone();
0670:
0671:                    if (past2FutureTbl.size() < maxCapacity)
0672:                        past2FutureTbl.put(updatedRL, updatedRL);
0673:                    else {
0674:                        tableScan.skipFutureRowHolder = true;
0675:                        ExecRow rlRow = new ValueRow(1);
0676:
0677:                        for (;;) {
0678:                            ExecRow aRow = tableScan.getNextRowCore();
0679:                            if (aRow == null) {
0680:                                tableScan.sourceDrained = true;
0681:                                tableScan.past2FutureTbl = null; // de-reference for garbage coll.
0682:                                break;
0683:                            }
0684:                            RowLocation rowLoc = (RowLocation) aRow
0685:                                    .getColumn(aRow.nColumns());
0686:
0687:                            if (updatedRL.equals(rowLoc)) //this row we are updating jumped forward
0688:                            {
0689:                                saveLastCusorKey(tableScan, aRow);
0690:                                break; // don't need to worry about adding this row to hash any more
0691:                            }
0692:
0693:                            if (tableScan.futureForUpdateRows == null) {
0694:                                // virtual memory heap. In-memory part size 100. With the co-operation
0695:                                // of hash table and in-memory part of heap (hash table shrinks while
0696:                                // in-memory heap grows), hopefully we never spill temp table to disk.
0697:
0698:                                tableScan.futureForUpdateRows = new TemporaryRowHolderImpl(
0699:                                        activation, null, null, 100, false,
0700:                                        true);
0701:                            }
0702:
0703:                            rlRow.setColumn(1, rowLoc);
0704:                            tableScan.futureForUpdateRows.insert(rlRow);
0705:                            if (past2FutureTbl.size() < maxCapacity) //we got space in the hash table now, stop!
0706:                            {
0707:                                past2FutureTbl.put(updatedRL, updatedRL);
0708:                                saveLastCusorKey(tableScan, aRow);
0709:                                break;
0710:                            }
0711:                        }
0712:                        tableScan.skipFutureRowHolder = false;
0713:                    }
0714:                }
0715:            }
0716:
0717:            private void saveLastCusorKey(TableScanResultSet tableScan,
0718:                    ExecRow aRow) throws StandardException {
0719:                /* We save the most-forward cursor scan key where we are stopping, so
0720:                 * that next time when we decide if we need to put an updated row id into
0721:                 * hash table, we can compare with this key.  This is an optimization on
0722:                 * memory usage of the hash table, otherwise it may be "leaking".
0723:                 */
0724:                if (tableScan.lastCursorKey == null)
0725:                    tableScan.lastCursorKey = new ValueRow(aRow.nColumns() - 1);
0726:                for (int i = 1; i <= tableScan.lastCursorKey.nColumns(); i++) {
0727:                    DataValueDescriptor aCol = aRow.getColumn(i);
0728:                    if (aCol != null)
0729:                        tableScan.lastCursorKey.setColumn(i, aCol.getClone());
0730:                }
0731:            }
0732:
0733:            void fireBeforeTriggers() throws StandardException {
0734:                if (deferred) {
0735:                    if (triggerInfo != null) {
0736:                        if (triggerActivator == null) {
0737:                            triggerActivator = new TriggerEventActivator(lcc,
0738:                                    tc, constants.targetUUID, triggerInfo,
0739:                                    TriggerExecutionContext.UPDATE_EVENT,
0740:                                    activation, null);
0741:                        } else {
0742:                            triggerActivator.reopen();
0743:                        }
0744:
0745:                        // fire BEFORE trigger, do this before checking constraints
0746:                        triggerActivator.notifyEvent(
0747:                                TriggerEvents.BEFORE_UPDATE, deletedRowHolder
0748:                                        .getResultSet(), insertedRowHolder
0749:                                        .getResultSet());
0750:
0751:                    }
0752:                }
0753:            }
0754:
0755:            void fireAfterTriggers() throws StandardException {
0756:                if (deferred) {
0757:                    if (triggerActivator != null) {
0758:                        triggerActivator.notifyEvent(
0759:                                TriggerEvents.AFTER_UPDATE, deletedRowHolder
0760:                                        .getResultSet(), insertedRowHolder
0761:                                        .getResultSet());
0762:                    }
0763:                }
0764:            }
0765:
0766:            void updateDeferredRows() throws StandardException {
0767:                if (deferred) {
0768:                    // we already have everything locked 
0769:                    deferredBaseCC = tc.openCompiledConglomerate(false,
0770:                            tc.OPENMODE_FORUPDATE
0771:                                    | tc.OPENMODE_SECONDARY_LOCKED, lockMode,
0772:                            TransactionController.ISOLATION_SERIALIZABLE,
0773:                            constants.heapSCOCI, heapDCOCI);
0774:
0775:                    CursorResultSet rs = insertedRowHolder.getResultSet();
0776:                    try {
0777:                        /*
0778:                         ** We need to do a fetch doing a partial row
0779:                         ** read.  We need to shift our 1-based bit
0780:                         ** set to a zero based bit set like the store
0781:                         ** expects.
0782:                         */
0783:                        FormatableBitSet readBitSet = RowUtil.shift(
0784:                                baseRowReadList, 1);
0785:                        ExecRow deferredTempRow2;
0786:
0787:                        rs.open();
0788:                        while ((deferredTempRow2 = rs.getNextRow()) != null) {
0789:                            /*
0790:                             ** Check the constraint now if we have triggers.
0791:                             ** Otherwise we evaluated them as we read the
0792:                             ** rows in from the source.
0793:                             */
0794:                            if (triggerInfo != null) {
0795:                                source.setCurrentRow(deferredTempRow);
0796:                                evaluateCheckConstraints(checkGM, activation);
0797:                            }
0798:
0799:                            /* 
0800:                             ** The last column is a Ref, which contains a 
0801:                             ** RowLocation.
0802:                             */
0803:                            DataValueDescriptor rlColumn = deferredTempRow2
0804:                                    .getColumn(numberOfBaseColumns + 1);
0805:                            RowLocation baseRowLocation = (RowLocation) (rlColumn)
0806:                                    .getObject();
0807:
0808:                            /* Get the base row at the given RowLocation */
0809:                            boolean row_exists = deferredBaseCC.fetch(
0810:                                    baseRowLocation, deferredSparseRow
0811:                                            .getRowArray(), readBitSet);
0812:
0813:                            if (SanityManager.DEBUG) {
0814:                                SanityManager
0815:                                        .ASSERT(row_exists,
0816:                                                "did not find base row in deferred update");
0817:                            }
0818:
0819:                            /*
0820:                             ** Copy the columns from the temp row to the base row.
0821:                             ** The base row has fewer columns than the temp row,
0822:                             ** because it doesn't contain the row location.
0823:                             */
0824:                            RowUtil.copyRefColumns(newBaseRow,
0825:                                    deferredTempRow2, numberOfBaseColumns);
0826:
0827:                            rowChanger.updateRow(deferredBaseRow, newBaseRow,
0828:                                    baseRowLocation);
0829:                            source.updateRow(newBaseRow);
0830:                        }
0831:                    } finally {
0832:                        source.clearCurrentRow();
0833:                        rs.close();
0834:                    }
0835:                }
0836:            }
0837:
0838:            void runChecker(boolean restrictCheckOnly) throws StandardException {
0839:
0840:                /*
0841:                 ** For a deferred update, make sure that there
0842:                 ** aren't any primary keys that were removed which
0843:                 ** are referenced.  
0844:                 */
0845:                if (deferred && updatingReferencedKey) {
0846:                    ExecRow deletedRow;
0847:                    CursorResultSet deletedRows;
0848:
0849:                    /*
0850:                     ** For each referenced key that was modified
0851:                     */
0852:                    for (int i = 0; i < fkInfoArray.length; i++) {
0853:                        if (fkInfoArray[i].type == FKInfo.FOREIGN_KEY) {
0854:                            continue;
0855:                        }
0856:
0857:                        deletedRows = deletedRowHolder.getResultSet();
0858:                        try {
0859:                            /*
0860:                             ** For each delete row
0861:                             */
0862:                            deletedRows.open();
0863:                            while ((deletedRow = deletedRows.getNextRow()) != null) {
0864:                                if (!foundRow(deletedRow,
0865:                                        fkInfoArray[i].colArray,
0866:                                        insertedRowHolder)) {
0867:                                    riChecker.doRICheck(i, deletedRow,
0868:                                            restrictCheckOnly);
0869:                                }
0870:                            }
0871:                        } finally {
0872:                            deletedRows.close();
0873:                        }
0874:                    }
0875:                }
0876:
0877:                /*
0878:                 ** For a deferred update, make sure that there
0879:                 ** aren't any foreign keys that were added that
0880:                 ** aren't referenced.  
0881:                 */
0882:                if (deferred && updatingForeignKey) {
0883:                    ExecRow insertedRow;
0884:                    CursorResultSet insertedRows;
0885:
0886:                    /*
0887:                     ** For each foreign key that was modified
0888:                     */
0889:                    for (int i = 0; i < fkInfoArray.length; i++) {
0890:                        if (fkInfoArray[i].type == FKInfo.REFERENCED_KEY) {
0891:                            continue;
0892:                        }
0893:
0894:                        insertedRows = insertedRowHolder.getResultSet();
0895:                        try {
0896:                            /*
0897:                             ** For each inserted row
0898:                             */
0899:                            insertedRows.open();
0900:                            while ((insertedRow = insertedRows.getNextRow()) != null) {
0901:                                if (!foundRow(insertedRow,
0902:                                        fkInfoArray[i].colArray,
0903:                                        deletedRowHolder)) {
0904:                                    riChecker.doRICheck(i, insertedRow,
0905:                                            restrictCheckOnly);
0906:                                }
0907:                            }
0908:                        } finally {
0909:                            insertedRows.close();
0910:                        }
0911:                    }
0912:                }
0913:
0914:            }
0915:
0916:            public static boolean foundRow(ExecRow checkRow, int[] colsToCheck,
0917:                    TemporaryRowHolderImpl rowHolder) throws StandardException {
0918:                ExecRow scanRow;
0919:                boolean foundMatch = false;
0920:                Object[] checkRowArray = checkRow.getRowArray();
0921:                DataValueDescriptor checkCol;
0922:                DataValueDescriptor scanCol;
0923:
0924:                CursorResultSet rs = rowHolder.getResultSet();
0925:                try {
0926:                    /*
0927:                     ** For each inserted row
0928:                     */
0929:                    rs.open();
0930:                    while ((scanRow = rs.getNextRow()) != null) {
0931:                        Object[] scanRowArray = scanRow.getRowArray();
0932:                        int i;
0933:                        for (i = 0; i < colsToCheck.length; i++) {
0934:                            checkCol = (DataValueDescriptor) checkRowArray[colsToCheck[i] - 1];
0935:                            scanCol = (DataValueDescriptor) scanRowArray[colsToCheck[i] - 1];
0936:
0937:                            BooleanDataValue result = checkCol.equals(scanCol,
0938:                                    checkCol); // result
0939:                            if (!result.getBoolean()) {
0940:                                break;
0941:                            }
0942:                        }
0943:                        if (i == colsToCheck.length) {
0944:                            foundMatch = true;
0945:                            break;
0946:                        }
0947:                    }
0948:                } finally {
0949:                    rs.close();
0950:                }
0951:                return foundMatch;
0952:            }
0953:
0954:            /**
0955:             * @see ResultSet#cleanUp
0956:             *
0957:             * @exception StandardException		Thrown on error
0958:             */
0959:            public void cleanUp() throws StandardException {
0960:                numOpens = 0;
0961:
0962:                /* Close down the source ResultSet tree */
0963:                if (source != null) {
0964:                    source.close();
0965:                    // cache source across open()s
0966:                }
0967:
0968:                if (triggerActivator != null) {
0969:                    triggerActivator.cleanup();
0970:                    // cache triggerActivator across open()s
0971:                }
0972:
0973:                if (rowChanger != null)
0974:                    rowChanger.close();
0975:
0976:                if (deferredBaseCC != null)
0977:                    deferredBaseCC.close();
0978:                deferredBaseCC = null;
0979:
0980:                if (insertedRowHolder != null) {
0981:                    insertedRowHolder.close();
0982:                }
0983:
0984:                if (deletedRowHolder != null) {
0985:                    deletedRowHolder.close();
0986:                }
0987:
0988:                if (riChecker != null) {
0989:                    riChecker.close();
0990:                    // cache riChecker across open()s
0991:                }
0992:
0993:                super .close();
0994:
0995:                endTime = getCurrentTimeMillis();
0996:            }
0997:
0998:            /**
0999:             * Decode the update lock mode.
1000:             * <p>
1001:             * The value for update lock mode is in the 2nd 2 bytes for 
1002:             * ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL isolation level.  Otherwise
1003:             * (REPEATABLE READ, READ COMMITTED, and READ UNCOMMITTED) the lock mode is
1004:             * located in the first 2 bytes.
1005:             * <p>
1006:             * This is done to override the optimizer choice to provide maximum 
1007:             * concurrency of record level locking except in SERIALIZABLE where table
1008:             * level locking is required in heap scans for correctness.
1009:             * <p>
1010:             * See Compilation!QueryTree!FromBaseTable for encoding of the lockmode.
1011:             * <p>
1012:             *
1013:             * @return The lock mode (record or table) to use to open the result set.
1014:             *
1015:             * @param lcc       The context to look for current isolation level.
1016:             * @param lockMode  The compiled encoded lock mode for this query.
1017:             *
1018:             * @exception  StandardException  Standard exception policy.
1019:             **/
1020:            protected static int decodeLockMode(LanguageConnectionContext lcc,
1021:                    int lockMode) {
1022:                if ((lockMode >>> 16) != 0) {
1023:                    // Note that isolation level encoding from 
1024:                    // getCurrentIsolationLevel() returns 
1025:                    // ExecutionContext.*ISOLATION_LEVEL constants, not 
1026:                    // TransactionController.ISOLATION* constants.
1027:
1028:                    int isolationLevel = lcc.getCurrentIsolationLevel();
1029:
1030:                    if (isolationLevel != ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL) {
1031:                        lockMode = lockMode & 0xff;
1032:                    } else {
1033:                        lockMode = lockMode >>> 16;
1034:                    }
1035:                }
1036:                return lockMode;
1037:            }
1038:
1039:            void rowChangerFinish() throws StandardException {
1040:                rowChanger.finish();
1041:            }
1042:
1043:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.