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


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.store.access.btree.BTreeScan
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.store.access.btree;
0023:
0024:        import org.apache.derby.iapi.reference.SQLState;
0025:
0026:        import org.apache.derby.iapi.services.sanity.SanityManager;
0027:        import org.apache.derby.iapi.services.io.Storable;
0028:
0029:        import org.apache.derby.iapi.error.StandardException;
0030:
0031:        import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
0032:        import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
0033:        import org.apache.derby.iapi.store.access.conglomerate.ScanManager;
0034:        import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
0035:
0036:        import org.apache.derby.iapi.store.access.ConglomerateController;
0037:        import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
0038:        import org.apache.derby.iapi.store.access.GenericScanController;
0039:        import org.apache.derby.iapi.store.access.Qualifier;
0040:        import org.apache.derby.iapi.store.access.RowUtil;
0041:        import org.apache.derby.iapi.store.access.ScanController;
0042:        import org.apache.derby.iapi.store.access.ScanInfo;
0043:        import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
0044:        import org.apache.derby.iapi.store.access.TransactionController;
0045:
0046:        import org.apache.derby.iapi.store.raw.ContainerHandle;
0047:        import org.apache.derby.iapi.store.raw.FetchDescriptor;
0048:        import org.apache.derby.iapi.store.raw.LockingPolicy;
0049:        import org.apache.derby.iapi.store.raw.Page;
0050:        import org.apache.derby.iapi.store.raw.RecordHandle;
0051:        import org.apache.derby.iapi.store.raw.Transaction;
0052:
0053:        import org.apache.derby.iapi.types.DataValueDescriptor;
0054:
0055:        import org.apache.derby.iapi.types.RowLocation;
0056:
0057:        import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;
0058:        import org.apache.derby.impl.store.access.conglomerate.TemplateRow;
0059:
0060:        import org.apache.derby.iapi.services.io.FormatableBitSet;
0061:        import org.apache.derby.iapi.store.access.BackingStoreHashtable;
0062:
0063:        /**
0064:
0065:         A b-tree scan controller corresponds to an instance of an open b-tree scan.
0066:         <P>
0067:         <B>Concurrency Notes<\B>
0068:         <P>
0069:         The concurrency rules are derived from OpenBTree.
0070:         <P>
0071:         @see OpenBTree
0072:
0073:         **/
0074:
0075:        public abstract class BTreeScan extends OpenBTree implements 
0076:                ScanManager {
0077:
0078:            /*
0079:             ** Fields of BTreeScan
0080:             */
0081:
0082:            /**
0083:             * init_startKeyValue, init_qualifier, and init_stopKeyValue all are used 
0084:             * to store * references to the values passed in when ScanController.init()
0085:             * is called.  It is assumed that these are not altered by the client
0086:             * while the scan is active.
0087:             */
0088:            protected Transaction init_rawtran = null;
0089:            protected boolean init_forUpdate;
0090:            protected FormatableBitSet init_scanColumnList;
0091:            protected DataValueDescriptor[] init_template;
0092:            protected DataValueDescriptor[] init_startKeyValue;
0093:            protected int init_startSearchOperator = 0;
0094:            protected Qualifier init_qualifier[][] = null;
0095:            protected DataValueDescriptor[] init_stopKeyValue;
0096:            protected int init_stopSearchOperator = 0;
0097:            protected boolean init_hold;
0098:
0099:            /**
0100:             * The fetch descriptor which describes the row to be returned by the scan.
0101:             **/
0102:            protected FetchDescriptor init_fetchDesc;
0103:
0104:            /**
0105:             * A constant FetchDescriptor which describes the position of the 
0106:             * RowLocation field within the btree, currently always the last column).  
0107:             * Used by lock/unlock to fetch the RowLocation.  
0108:             * Only needs to be allocated once per scan.
0109:             **/
0110:            protected FetchDescriptor init_lock_fetch_desc;
0111:
0112:            BTreeRowPosition scan_position;
0113:
0114:            /**
0115:             * Whether the scan should requests UPDATE locks which then will be 
0116:             * converted to X locks when the actual operation is performed.
0117:             **/
0118:            protected boolean init_useUpdateLocks = false;
0119:
0120:            /*
0121:             * There are 5 states a scan can be in.
0122:             *     SCAN_INIT - A scan has started but no positioning has been done.
0123:             *                 The scan will be positioned when the first next() call
0124:             *                 has been made.  None of the positioning state variables
0125:             *                 are valid in this state.
0126:             *     SCAN_INPROGRESS -
0127:             *                 A scan is in this state after the first next() call.
0128:             *                 On exit from any BTreeScan method, while in this state,
0129:             *                 the scan "points" at a row which qualifies for the 
0130:             *                 scan.  While not maintaining latches on a page the 
0131:             *                 current position of the scan is either kept by record
0132:             *                 handle or key.  To tell which use the following:
0133:             *                 if (record key == null)
0134:             *                    record handle has current position
0135:             *                 else
0136:             *                    record key has current position
0137:             *
0138:             *     SCAN_DONE - Once the end of the table or the stop condition is met
0139:             *                 then the scan is placed in this state.  Only valid 
0140:             *                 ScanController method at this point is close().
0141:             *
0142:             *     SCAN_HOLD_INIT -
0143:             *                 The scan has been opened and held open across a commit,
0144:             *                 at the last commit the state was SCAN_INIT.
0145:             *                 The scan has never progressed from the SCAN_INIT state
0146:             *                 during a transaction.  When a next is done the state
0147:             *                 will either progress to SCAN_INPROGRESS or SCAN_DONE.
0148:             *
0149:             *     SCAN_HOLD_INPROGRESS -
0150:             *                 The scan has been opened and held open across a commit,
0151:             *                 at the last commit the state was in SCAN_INPROGRESS.
0152:             *                 The transaction which opened the scan has committed,
0153:             *                 but the scan was opened with the "hold" option true.
0154:             *                 At commit the locks were released and the "current"
0155:             *                 position is remembered.  In this state only two calls
0156:             *                 are valid, either next() or close().  When next() is
0157:             *                 called the scan is reopened, the underlying container
0158:             *                 is opened thus associating all new locks with the current
0159:             *                 transaction, and the scan continues at the "next" row.
0160:             */
0161:            protected static final int SCAN_INIT = 1;
0162:            protected static final int SCAN_INPROGRESS = 2;
0163:            protected static final int SCAN_DONE = 3;
0164:            protected static final int SCAN_HOLD_INIT = 4;
0165:            protected static final int SCAN_HOLD_INPROGRESS = 5;
0166:
0167:            /**
0168:             * Delay positioning the  table at the start position until the first
0169:             * next() call.  The initial position is done in positionAtStartPosition().
0170:             */
0171:            protected int scan_state = SCAN_INIT;
0172:
0173:            /**
0174:             * Performance counters ...
0175:             */
0176:            protected int stat_numpages_visited = 0;
0177:            protected int stat_numrows_visited = 0;
0178:            protected int stat_numrows_qualified = 0;
0179:            protected int stat_numdeleted_rows_visited = 0;
0180:
0181:            /**
0182:             * What kind of row locks to get during the scan.
0183:             **/
0184:            protected int lock_operation;
0185:
0186:            /**
0187:             * A 1 element array to turn fetchNext and fetch calls into 
0188:             * fetchNextGroup calls.
0189:             **/
0190:            protected DataValueDescriptor[][] fetchNext_one_slot_array = new DataValueDescriptor[1][];
0191:
0192:            /* Constructors for This class: */
0193:
0194:            public BTreeScan() {
0195:            }
0196:
0197:            /*
0198:             ** Private/Protected methods of This class, sorted alphabetically
0199:             */
0200:
0201:            /**
0202:             * Fetch the next N rows from the table.
0203:             * <p>
0204:             * Utility routine used by both fetchSet() and fetchNextGroup().
0205:             *
0206:             * @exception  StandardException  Standard exception policy.
0207:             **/
0208:            abstract protected int fetchRows(BTreeRowPosition pos,
0209:                    DataValueDescriptor[][] row_array,
0210:                    RowLocation[] rowloc_array,
0211:                    BackingStoreHashtable hash_table, long max_rowcnt,
0212:                    int[] key_column_numbers) throws StandardException;
0213:
0214:            /**
0215:             * Shared initialization code between init() and reopenScan().
0216:             * <p>
0217:             * Basically save away input parameters describing qualifications for
0218:             * the scan, and do some error checking.
0219:             *
0220:             * @exception  StandardException  Standard exception policy.
0221:             **/
0222:            private void initScanParams(DataValueDescriptor[] startKeyValue,
0223:                    int startSearchOperator, Qualifier qualifier[][],
0224:                    DataValueDescriptor[] stopKeyValue, int stopSearchOperator)
0225:                    throws StandardException {
0226:                // startKeyValue init.
0227:                this .init_startKeyValue = startKeyValue;
0228:                if (RowUtil.isRowEmpty(this .init_startKeyValue))
0229:                    this .init_startKeyValue = null;
0230:
0231:                // startSearchOperator init.
0232:                this .init_startSearchOperator = startSearchOperator;
0233:
0234:                // qualifier init.
0235:                if ((qualifier != null) && (qualifier.length == 0))
0236:                    qualifier = null;
0237:                this .init_qualifier = qualifier;
0238:
0239:                // stopKeyValue init.
0240:                this .init_stopKeyValue = stopKeyValue;
0241:                if (RowUtil.isRowEmpty(this .init_stopKeyValue))
0242:                    this .init_stopKeyValue = null;
0243:
0244:                // stopSearchOperator init.
0245:                this .init_stopSearchOperator = stopSearchOperator;
0246:
0247:                // reset the "current" position to starting condition.
0248:                // RESOLVE (mmm) - "compile" this.
0249:                scan_position = new BTreeRowPosition();
0250:
0251:                scan_position.init();
0252:
0253:                scan_position.current_lock_template = new DataValueDescriptor[this .init_template.length];
0254:
0255:                scan_position.current_lock_template[this .init_template.length - 1] = scan_position.current_lock_row_loc = (RowLocation) ((RowLocation) init_template[init_template.length - 1])
0256:                        .cloneObject();
0257:
0258:                // Verify that all columns in start key value, stop key value, and
0259:                // qualifiers are present in the list of columns described by the
0260:                // scanColumnList.
0261:                if (SanityManager.DEBUG) {
0262:                    if (init_scanColumnList != null) {
0263:                        // verify that all columns specified in qualifiers, start
0264:                        // and stop positions are specified in the scanColumnList.  
0265:
0266:                        FormatableBitSet required_cols;
0267:
0268:                        if (qualifier != null)
0269:                            required_cols = RowUtil
0270:                                    .getQualifierBitSet(qualifier);
0271:                        else
0272:                            required_cols = new FormatableBitSet(0);
0273:
0274:                        // add in start columns
0275:                        if (this .init_startKeyValue != null) {
0276:                            required_cols.grow(this .init_startKeyValue.length);
0277:                            for (int i = 0; i < this .init_startKeyValue.length; i++)
0278:                                required_cols.set(i);
0279:                        }
0280:
0281:                        if (this .init_stopKeyValue != null) {
0282:                            required_cols.grow(this .init_stopKeyValue.length);
0283:                            for (int i = 0; i < this .init_stopKeyValue.length; i++)
0284:                                required_cols.set(i);
0285:                        }
0286:
0287:                        FormatableBitSet required_cols_and_scan_list = (FormatableBitSet) required_cols
0288:                                .clone();
0289:
0290:                        required_cols_and_scan_list.and(init_scanColumnList);
0291:
0292:                        // FormatableBitSet equals requires the two FormatableBitSets to be of same
0293:                        // length.
0294:                        required_cols.grow(init_scanColumnList.size());
0295:
0296:                        if (!required_cols_and_scan_list.equals(required_cols)) {
0297:                            SanityManager
0298:                                    .THROWASSERT("Some column specified in a Btree "
0299:                                            + " qualifier/start/stop list is "
0300:                                            + "not represented in the scanColumnList."
0301:                                            + "\n:required_cols_and_scan_list = "
0302:                                            + required_cols_and_scan_list
0303:                                            + "\n;required_cols = "
0304:                                            + required_cols
0305:                                            + "\n;init_scanColumnList = "
0306:                                            + init_scanColumnList);
0307:                        }
0308:                    }
0309:                }
0310:            }
0311:
0312:            /**
0313:             * Position scan at "start" position for a forward scan.
0314:             * <p> 
0315:             * Positions the scan to the slot just before the first record to be 
0316:             * returned from the scan.  Returns the start page latched, and 
0317:             * sets "current_slot" to the slot number.
0318:             * <p>
0319:             *
0320:             * @exception  StandardException  Standard exception policy.
0321:             **/
0322:            protected void positionAtStartForForwardScan(BTreeRowPosition pos)
0323:                    throws StandardException {
0324:                boolean exact;
0325:
0326:                // This routine should only be called from first next() call //
0327:                if (SanityManager.DEBUG) {
0328:                    SanityManager.ASSERT((scan_state == SCAN_INIT)
0329:                            || (scan_state == SCAN_HOLD_INIT));
0330:                    SanityManager.ASSERT(pos.current_rh == null);
0331:                    SanityManager.ASSERT(pos.current_positionKey == null);
0332:                    SanityManager.ASSERT(pos.current_scan_pageno == 0);
0333:                }
0334:
0335:                // Loop until you can lock the row previous to the first row to be
0336:                // returned by the scan, while holding the page latched, without
0337:                // waiting.  If you have to wait, drop the latch, wait for the lock -
0338:                // which makes it likely if you wait for the lock you will loop just
0339:                // once, find the same lock satisfies the search and since you already
0340:                // have the lock it will be granted.
0341:                while (true) {
0342:                    // Find the starting page and row slot, must start at root and
0343:                    // search either for leftmost leaf, or search for specific key.
0344:                    ControlRow root = ControlRow.Get(this , BTree.ROOTPAGEID);
0345:
0346:                    // include search of tree in page visited stats.
0347:                    stat_numpages_visited += root.getLevel() + 1;
0348:
0349:                    boolean need_previous_lock = true;
0350:
0351:                    if (init_startKeyValue == null) {
0352:                        // No start given, so position at 0 slot of leftmost leaf page
0353:                        pos.current_leaf = (LeafControlRow) root
0354:                                .searchLeft(this );
0355:
0356:                        pos.current_slot = ControlRow.CR_SLOT;
0357:                        exact = false;
0358:                    } else {
0359:                        // Search for the starting row.
0360:
0361:                        if (SanityManager.DEBUG)
0362:                            SanityManager
0363:                                    .ASSERT((init_startSearchOperator == ScanController.GE)
0364:                                            || (init_startSearchOperator == ScanController.GT));
0365:
0366:                        SearchParameters sp = new SearchParameters(
0367:                                init_startKeyValue,
0368:                                ((init_startSearchOperator == ScanController.GE) ? SearchParameters.POSITION_LEFT_OF_PARTIAL_KEY_MATCH
0369:                                        : SearchParameters.POSITION_RIGHT_OF_PARTIAL_KEY_MATCH),
0370:                                init_template, this , false);
0371:
0372:                        pos.current_leaf = (LeafControlRow) root.search(sp);
0373:
0374:                        pos.current_slot = sp.resultSlot;
0375:                        exact = sp.resultExact;
0376:
0377:                        // The way that scans are used, the caller calls next()
0378:                        // to position on the first row.  If the result of the
0379:                        // search that found the starting page and slot was not
0380:                        // exact, then the page/slot will refer to the row before
0381:                        // the first qualifying row.  The first call to next()
0382:                        // will therefore move to the first (potentially) qualifying
0383:                        // row.  However, if the search was exact, then we don't
0384:                        // want to move the position on the first call to next.
0385:                        // In that case, by decrementing the slot, the first call
0386:                        // to next will put us back	on the starting row.
0387:
0388:                        if (exact
0389:                                && init_startSearchOperator == ScanController.GE) {
0390:                            pos.current_slot--;
0391:
0392:                            // A scan on a unique index, with a start position of
0393:                            // GE, need not get a previous key lock to protect the
0394:                            // range.  Since it is unique no other key can go before
0395:                            // the first row returned from the scan.
0396:                            //
0397:                            // RESOLVE - currently btree's only support allowDuplicates
0398:                            // of "false", so no need to do the extra check, current
0399:                            // btree implementation depends on RowLocation field
0400:                            // making every key unique (duplicate indexes are supported
0401:                            // by the nUniqueColumns and nKeyFields). 
0402:                            if (getConglomerate().nUniqueColumns < getConglomerate().nKeyFields) {
0403:                                // this implies unique index, thus no prev key.
0404:                                need_previous_lock = false;
0405:                            }
0406:                        }
0407:                    }
0408:
0409:                    boolean latch_released = false;
0410:                    if (need_previous_lock) {
0411:                        latch_released = !this .getLockingPolicy().lockScanRow(
0412:                                this , this .getConglomerate(), pos, true,
0413:                                init_lock_fetch_desc,
0414:                                pos.current_lock_template,
0415:                                pos.current_lock_row_loc, true, init_forUpdate,
0416:                                lock_operation);
0417:                    } else {
0418:                        // Don't need to lock the "previous key" but still need to get
0419:                        // the scan lock to protect the position in the btree.
0420:
0421:                        latch_released = !this .getLockingPolicy().lockScan(
0422:                                pos.current_leaf, // the page we are positioned on.
0423:                                (ControlRow) null, // no other page to unlatch
0424:                                false, // lock for read.
0425:                                lock_operation); // not used.
0426:                    }
0427:
0428:                    // special test to see if latch release code works
0429:                    if (SanityManager.DEBUG) {
0430:                        latch_released = test_errors(this ,
0431:                                "BTreeScan_positionAtStartPosition", true, this 
0432:                                        .getLockingPolicy(), pos.current_leaf,
0433:                                latch_released);
0434:                    }
0435:
0436:                    if (latch_released) {
0437:                        // lost latch on pos.current_leaf, search the tree again.
0438:                        pos.current_leaf = null;
0439:                        continue;
0440:                    } else {
0441:                        // success! got all the locks, while holding the latch.
0442:                        break;
0443:                    }
0444:                }
0445:
0446:                this .scan_state = SCAN_INPROGRESS;
0447:                pos.current_scan_pageno = pos.current_leaf.page.getPageNumber();
0448:                pos.current_slot = pos.current_slot;
0449:
0450:                if (SanityManager.DEBUG)
0451:                    SanityManager.ASSERT(pos.current_leaf != null);
0452:            }
0453:
0454:            /**
0455:             * Position scan at "start" position for a backward scan.
0456:             * <p>
0457:             * Positions the scan to the slot just after the first record to be 
0458:             * returned from the backward scan.  Returns the start page latched, and 
0459:             * sets "current_slot" to the slot number just right of the first slot
0460:             * to return.
0461:             * <p>
0462:             *
0463:             * @exception  StandardException  Standard exception policy.
0464:             **/
0465:            protected void positionAtStartForBackwardScan(BTreeRowPosition pos)
0466:                    throws StandardException {
0467:                boolean exact;
0468:
0469:                // This routine should only be called from first next() call //
0470:                if (SanityManager.DEBUG) {
0471:                    SanityManager.ASSERT((this .scan_state == SCAN_INIT)
0472:                            || (this .scan_state == SCAN_HOLD_INIT));
0473:
0474:                    SanityManager.ASSERT(pos.current_rh == null);
0475:                    SanityManager.ASSERT(pos.current_positionKey == null);
0476:                    SanityManager.ASSERT(pos.current_scan_pageno == 0);
0477:                }
0478:
0479:                // Loop until you can lock the row previous to the first row to be
0480:                // returned by the scan, while holding the page latched, without
0481:                // waiting.  If you have to wait, drop the latch, wait for the lock -
0482:                // which makes it likely if you wait for the lock you will loop just
0483:                // once, find the same lock satisfies the search and since you already
0484:                // have the lock it will be granted.
0485:                while (true) {
0486:                    // Find the starting page and row slot, must start at root and
0487:                    // search either for leftmost leaf, or search for specific key.
0488:                    ControlRow root = ControlRow.Get(this , BTree.ROOTPAGEID);
0489:
0490:                    // include search of tree in page visited stats.
0491:                    stat_numpages_visited += root.getLevel() + 1;
0492:
0493:                    if (init_startKeyValue == null) {
0494:                        // No start given, position at last slot + 1 of rightmost leaf 
0495:                        pos.current_leaf = (LeafControlRow) root
0496:                                .searchRight(this );
0497:
0498:                        pos.current_slot = pos.current_leaf.page.recordCount();
0499:                        exact = false;
0500:                    } else {
0501:                        /*
0502:                        if (SanityManager.DEBUG)
0503:                            SanityManager.THROWASSERT(
0504:                                "Code not ready yet for positioned backward scans.");
0505:                         */
0506:
0507:                        if (SanityManager.DEBUG)
0508:                            SanityManager
0509:                                    .ASSERT((init_startSearchOperator == ScanController.GE)
0510:                                            || (init_startSearchOperator == ScanController.GT));
0511:
0512:                        // Search for the starting row.
0513:
0514:                        SearchParameters sp = new SearchParameters(
0515:                                init_startKeyValue,
0516:                                ((init_startSearchOperator == ScanController.GE) ? SearchParameters.POSITION_RIGHT_OF_PARTIAL_KEY_MATCH
0517:                                        : SearchParameters.POSITION_LEFT_OF_PARTIAL_KEY_MATCH),
0518:                                init_template, this , false);
0519:
0520:                        pos.current_leaf = (LeafControlRow) root.search(sp);
0521:
0522:                        pos.current_slot = sp.resultSlot;
0523:                        exact = sp.resultExact;
0524:
0525:                        // The way that backward scans are used, the caller calls next()
0526:                        // to position on the first row.  If the result of the
0527:                        // search that found the starting page and slot was not
0528:                        // exact, then the page/slot will refer to the row before
0529:                        // the first qualifying row.  The first call to next()
0530:                        // will therefore move to the first (potentially) qualifying
0531:                        // row.  However, if the search was exact, then we don't
0532:                        // want to move the position on the first call to next.
0533:                        // In that case, by decrementing the slot, the first call
0534:                        // to next will put us back	on the starting row.
0535:
0536:                        if (exact) {
0537:                            // the search has found exactly the start position key 
0538:                            if (init_startSearchOperator == ScanController.GE) {
0539:                                // insure backward scan returns this row by moving
0540:                                // slot to one after this row.
0541:                                pos.current_slot++;
0542:                            } else {
0543:                                // no work necessary leave startslot positioned on the
0544:                                // row, we will skip this record
0545:                                if (SanityManager.DEBUG)
0546:                                    SanityManager
0547:                                            .ASSERT(init_startSearchOperator == ScanController.GT);
0548:                            }
0549:                        } else {
0550:                            // the search positioned one before the start position key,
0551:                            // move it to one "after"
0552:                            pos.current_slot++;
0553:                        }
0554:                    }
0555:
0556:                    boolean latch_released = !this .getLockingPolicy()
0557:                            .lockScanRow(this , this .getConglomerate(), pos,
0558:                                    true, init_lock_fetch_desc,
0559:                                    pos.current_lock_template,
0560:                                    pos.current_lock_row_loc, true,
0561:                                    init_forUpdate, lock_operation);
0562:
0563:                    // special test to see if latch release code works
0564:                    if (SanityManager.DEBUG) {
0565:                        latch_released = test_errors(this ,
0566:                                "BTreeScan_positionAtStartPosition", true, this 
0567:                                        .getLockingPolicy(), pos.current_leaf,
0568:                                latch_released);
0569:                    }
0570:
0571:                    if (latch_released) {
0572:                        // lost latch on pos.current_leaf, search the tree again.
0573:                        pos.current_leaf = null;
0574:                        continue;
0575:                    } else {
0576:                        // success! got all the locks, while holding the latch.
0577:                        break;
0578:                    }
0579:                }
0580:
0581:                this .scan_state = SCAN_INPROGRESS;
0582:                pos.current_scan_pageno = pos.current_leaf.page.getPageNumber();
0583:
0584:                if (SanityManager.DEBUG)
0585:                    SanityManager.ASSERT(pos.current_leaf != null);
0586:
0587:                // System.out.println("backward scan end start position: " +
0588:                //       " current_slot = " + this.current_slot );
0589:            }
0590:
0591:            /**
0592:             * Position scan to 0 slot on next page.
0593:             * <p>
0594:             * Position to next page, keeping latch on previous page until we have 
0595:             * latch on next page.  This routine releases the latch on current_page
0596:             * once it has successfully gotten both the latch on the next page and
0597:             * the scan lock on the next page.
0598:             *
0599:             * @param pos           current row position of the scan.
0600:             *
0601:             * @exception  StandardException  Standard exception policy.
0602:             **/
0603:            protected void positionAtNextPage(BTreeRowPosition pos)
0604:                    throws StandardException {
0605:                // RESOLVE (mikem) - not sure but someday in the future this
0606:                // assert may not be true, but for now we always have the scan
0607:                // lock when we call this routine.
0608:                if (SanityManager.DEBUG)
0609:                    SanityManager.ASSERT(pos.current_scan_pageno != 0);
0610:
0611:                while (true) {
0612:                    if ((pos.next_leaf = (LeafControlRow) pos.current_leaf
0613:                            .getRightSibling(this )) == null) {
0614:                        break;
0615:                    }
0616:
0617:                    boolean latch_released = !this .getLockingPolicy().lockScan(
0618:                            pos.next_leaf,
0619:                            (LeafControlRow) null, // no other latch currently
0620:                            false /* not for update */,
0621:                            ConglomerateController.LOCK_READ); // get read scan lock.
0622:
0623:                    // TESTING CODE:
0624:                    if (SanityManager.DEBUG) {
0625:                        latch_released = test_errors(this ,
0626:                                "BTreeScan_positionAtNextPage", true, this 
0627:                                        .getLockingPolicy(), pos.next_leaf,
0628:                                latch_released);
0629:                    }
0630:
0631:                    if (!latch_released) {
0632:                        break;
0633:                    }
0634:                }
0635:
0636:                // Now that we either have both latch and scan lock on next leaf, or 
0637:                // there is no next leaf we can release scan and latch on current page.
0638:                if (SanityManager.DEBUG) {
0639:                    if (pos.current_scan_pageno != pos.current_leaf.page
0640:                            .getPageNumber())
0641:                        SanityManager.THROWASSERT("pos.current_scan_pageno = "
0642:                                + pos.current_scan_pageno
0643:                                + "pos.current_leaf = " + pos.current_leaf);
0644:                }
0645:
0646:                // unlock the previous row if doing read.
0647:                if (pos.current_rh != null) {
0648:                    this .getLockingPolicy().unlockScanRecordAfterRead(pos,
0649:                            init_forUpdate);
0650:                }
0651:
0652:                this .getLockingPolicy().unlockScan(
0653:                        pos.current_leaf.page.getPageNumber());
0654:                pos.current_leaf.release();
0655:                pos.current_leaf = pos.next_leaf;
0656:
0657:                pos.current_scan_pageno = (pos.next_leaf == null) ? 0
0658:                        : pos.next_leaf.page.getPageNumber();
0659:
0660:                // set up for scan to continue at beginning of next page.
0661:                pos.current_slot = Page.FIRST_SLOT_NUMBER;
0662:                pos.current_rh = null;
0663:            }
0664:
0665:            /**
0666:            Position scan at "start" position.
0667:            <p>
0668:            Positions the scan to the slot just before the first record to be returned
0669:            from the scan.  Returns the start page latched, and sets "current_slot" to
0670:            the slot number.
0671:
0672:            @exception  StandardException  Standard exception policy.
0673:             **/
0674:            abstract void positionAtStartPosition(BTreeRowPosition pos)
0675:                    throws StandardException;
0676:
0677:            /**
0678:             * Do any necessary work to complete the scan.
0679:             *
0680:             * @param pos           current row position of the scan.
0681:             *
0682:             * @exception  StandardException  Standard exception policy.
0683:             **/
0684:            protected void positionAtDoneScanFromClose(BTreeRowPosition pos)
0685:                    throws StandardException {
0686:                // call unlockScanRecordAfterRead() before closing, currently
0687:                // this is only important for releasing RR locks on non-qualified
0688:                // rows.   
0689:                //
0690:                // Otherwise the correct behavior happens as part of the close, ie.:
0691:                //
0692:                //     for READ_UNCOMMITTED there is no lock to release, 
0693:                //     for READ_COMMITTED   all read locks will be released, 
0694:                //     for REPEATABLE_READ or SERIALIZABLE no locks are released.
0695:
0696:                if ((pos.current_rh != null) && !pos.current_rh_qualified) {
0697:                    if (pos.current_leaf == null
0698:                            || pos.current_leaf.page == null) {
0699:                        // If we are being called from a "normal" close then there
0700:                        // will be no latch on current_leaf, get it and do the the
0701:                        // unlock.  We may be called sometimes, after an error where
0702:                        // we may have the latch, in this case the transaction is about
0703:                        // to be backed out anyway so don't worry about doing this 
0704:                        // unlock (thus why we only do the following code if we
0705:                        // "don't" have lock, ie. pos.current_leaf== null).
0706:
0707:                        if (!reposition(pos, false)) {
0708:                            if (SanityManager.DEBUG) {
0709:                                SanityManager
0710:                                        .THROWASSERT("can not fail while holding update row lock.");
0711:                            }
0712:                        }
0713:
0714:                        this .getLockingPolicy().unlockScanRecordAfterRead(pos,
0715:                                init_forUpdate);
0716:
0717:                        pos.current_rh = null;
0718:                        pos.current_leaf.release();
0719:                        pos.current_leaf = null;
0720:                    }
0721:                }
0722:
0723:                // Need to do this unlock in any case, until lock manager provides
0724:                // a way to release locks associated with a compatibility space.  This
0725:                // scan lock is special, as it is a lock on the btree container rather
0726:                // than the heap container.  The open container on the btree actually
0727:                // has a null locking policy so the close of that container does not
0728:                // release this lock, need to explicitly unlock it here or when the
0729:                // scan is closed as part of the abort the lock will not be released.
0730:                if (pos.current_scan_pageno != 0) {
0731:                    this .getLockingPolicy().unlockScan(pos.current_scan_pageno);
0732:                    pos.current_scan_pageno = 0;
0733:                }
0734:
0735:                pos.current_slot = Page.INVALID_SLOT_NUMBER;
0736:                pos.current_rh = null;
0737:                pos.current_positionKey = null;
0738:                this .scan_state = SCAN_DONE;
0739:
0740:                return;
0741:            }
0742:
0743:            /**
0744:             * Do work necessary to close a scan.
0745:             * <p>
0746:             * This routine can only be called "inline" from other btree routines,
0747:             * as it counts on the state of the pos to be correct.
0748:             * <p>
0749:             * Closing a scan from close() must handle long jumps from exceptions
0750:             * where the state of pos may not be correct.  The easiest case is
0751:             * a lock timeout which has caused us not to have a latch on a page,
0752:             * but pos still thinks there is a latch.  This is the easiest but
0753:             * other exceptions can also caused the same state at close() time.
0754:             **/
0755:            protected void positionAtDoneScan(BTreeRowPosition pos)
0756:                    throws StandardException {
0757:
0758:                // Need to do this unlock in any case, until lock manager provides
0759:                // a way to release locks associated with a compatibility space.  This
0760:                // scan lock is special, as it is a lock on the btree container rather
0761:                // than the heap container.  The open container on the btree actually
0762:                // has a null locking policy so the close of that container does not
0763:                // release this lock, need to explicitly unlock it here or when the
0764:                // scan is closed as part of the abort the lock will not be released.
0765:                if (pos.current_scan_pageno != 0) {
0766:                    this .getLockingPolicy().unlockScan(pos.current_scan_pageno);
0767:                    pos.current_scan_pageno = 0;
0768:                }
0769:
0770:                pos.current_slot = Page.INVALID_SLOT_NUMBER;
0771:                pos.current_rh = null;
0772:                pos.current_positionKey = null;
0773:                this .scan_state = SCAN_DONE;
0774:
0775:                return;
0776:            }
0777:
0778:            /**
0779:             * process_qualifier - Determine if a row meets all qualifier conditions.
0780:             * <p>
0781:             * Check all qualifiers in the qualifier array against row.  Return true
0782:             * if all compares specified by the qualifier array return true, else
0783:             * return false.
0784:             * <p>
0785:             * It is up to caller to make sure qualifier list is non-null.
0786:             *
0787:             * @param row      The row with the same partial column list as the
0788:             *                 row returned by the current scan.
0789:             *
0790:             * @exception  StandardException  Standard exception policy.
0791:             */
0792:            protected boolean process_qualifier(DataValueDescriptor[] row)
0793:                    throws StandardException {
0794:                boolean row_qualifies = true;
0795:                Qualifier q;
0796:
0797:                // Process the 2-d qualifier which is structured as follows:
0798:                //
0799:                // A two dimensional array is to be used to pass around a AND's and OR's
0800:                // in conjunctive normal form (CNF).  The top slot of the 2 dimensional
0801:                // array is optimized for the more frequent where no OR's are present.  
0802:                // The first array slot is always a list of AND's to be treated as 
0803:                // described above for single dimensional AND qualifier arrays.  The 
0804:                // subsequent slots are to be treated as AND'd arrays or OR's.  Thus 
0805:                // the 2 dimensional array qual[][] argument is to be treated as the 
0806:                // following, note if qual.length = 1 then only the first array is 
0807:                // valid and // it is and an array of and clauses:
0808:                //
0809:                // (qual[0][0] and qual[0][0] ... and qual[0][qual[0].length - 1])
0810:                // and
0811:                // (qual[1][0] or  qual[1][1] ... or  qual[1][qual[1].length - 1])
0812:                // and
0813:                // (qual[2][0] or  qual[2][1] ... or  qual[2][qual[2].length - 1])
0814:                // ...
0815:                // and
0816:                // (qual[qual.length - 1][0] or  qual[1][1] ... or  qual[1][2])
0817:
0818:                // First do the qual[0] which is an array of qualifer terms.
0819:
0820:                if (SanityManager.DEBUG) {
0821:                    // routine should not be called if there is no qualifier
0822:                    SanityManager.ASSERT(this .init_qualifier != null);
0823:                    SanityManager.ASSERT(this .init_qualifier.length > 0);
0824:                }
0825:
0826:                for (int i = 0; i < this .init_qualifier[0].length; i++) {
0827:                    // process each AND clause 
0828:
0829:                    row_qualifies = false;
0830:
0831:                    // process each OR clause.
0832:
0833:                    q = this .init_qualifier[0][i];
0834:
0835:                    // Get the column from the possibly partial row, of the 
0836:                    // q.getColumnId()'th column in the full row.
0837:                    DataValueDescriptor columnValue = row[q.getColumnId()];
0838:
0839:                    row_qualifies = columnValue.compare(q.getOperator(), q
0840:                            .getOrderable(), q.getOrderedNulls(), q
0841:                            .getUnknownRV());
0842:
0843:                    if (q.negateCompareResult())
0844:                        row_qualifies = !row_qualifies;
0845:
0846:                    // Once an AND fails the whole Qualification fails - do a return!
0847:                    if (!row_qualifies)
0848:                        return (false);
0849:                }
0850:
0851:                // all the qual[0] and terms passed, now process the OR clauses
0852:
0853:                for (int and_idx = 1; and_idx < this .init_qualifier.length; and_idx++) {
0854:                    // process each AND clause 
0855:
0856:                    row_qualifies = false;
0857:
0858:                    if (SanityManager.DEBUG) {
0859:                        // Each OR clause must be non-empty.
0860:                        SanityManager
0861:                                .ASSERT(this .init_qualifier[and_idx].length > 0);
0862:                    }
0863:
0864:                    for (int or_idx = 0; or_idx < this .init_qualifier[and_idx].length; or_idx++) {
0865:                        // process each OR clause.
0866:
0867:                        q = this .init_qualifier[and_idx][or_idx];
0868:
0869:                        // Get the column from the possibly partial row, of the 
0870:                        // q.getColumnId()'th column in the full row.
0871:                        DataValueDescriptor columnValue = row[q.getColumnId()];
0872:
0873:                        row_qualifies = columnValue.compare(q.getOperator(), q
0874:                                .getOrderable(), q.getOrderedNulls(), q
0875:                                .getUnknownRV());
0876:
0877:                        if (q.negateCompareResult())
0878:                            row_qualifies = !row_qualifies;
0879:
0880:                        // once one OR qualifies the entire clause is TRUE
0881:                        if (row_qualifies)
0882:                            break;
0883:                    }
0884:
0885:                    if (!row_qualifies)
0886:                        break;
0887:                }
0888:
0889:                return (row_qualifies);
0890:            }
0891:
0892:            /**
0893:             * Reposition the scan leaving and reentering the access layer.
0894:             * <p>
0895:             * When a scan leaves access it saves the RecordHandle of the record
0896:             * on the page.  There are 2 cases to consider when trying to reposition
0897:             * the scan when re-entering access:
0898:             *     o ROW has not moved off the page.
0899:             *       If the row has not moved then the RecordHandle we have saved
0900:             *       away is valid, and we just call RawStore to reposition on that
0901:             *       RecordHandle (RawStore takes care of the row moving within
0902:             *       the page).
0903:             *     o ROW has moved off the page.
0904:             *       This can only happen in the case of a btree split.  In that
0905:             *       case the splitter will have caused all scans positioned on 
0906:             *       this page within the same transaction to save a copy of the
0907:             *       row that the scan was positioned on.  Then to reposition the
0908:             *       scan it is necessary to research the tree from the top using
0909:             *       the copy of the row.
0910:             *
0911:             * If the scan has saved it's position by key (and thus has given up the
0912:             * scan lock on the page), there are a few cases where it is possible that
0913:             * the key no longer exists in the table.  In the case of a scan held 
0914:             * open across commit it is easy to imagine that the row the scan was 
0915:             * positioned on could be deleted and subsequently purged from the table 
0916:             * all before the scan resumes.  Also in the case of read uncommitted 
0917:             * the scan holds no lock on the current row, so it could be purged -
0918:             * in the following scenario for instance:  read uncommitted transaction 1
0919:             * opens scan and positions on row (1,2), transaction 2 deletes (1,2) and
0920:             * commits, transaction 1 inserts (1,3) which goes to same page as (1,2)
0921:             * and is going to cause a split, transaction 1 saves scan position as
0922:             * key, gives up scan lock and then purges row (1, 2), when transaction 
0923:             * 1 resumes scan (1, 2) no longer exists.  missing_row_for_key_ok 
0924:             * parameter is added as a sanity check to make sure it ok that 
0925:             * repositioning does not go to same row that we were repositioned on.
0926:             *
0927:             *
0928:             *
0929:             * @param   pos                     position to set the scan to.
0930:             *
0931:             * @param   missing_row_for_key_ok  if true and exact key is not found then
0932:             *                                  scan is just set to key just left of
0933:             *                                  the key (thus a next will move to the
0934:             *                                  key just after "pos")
0935:             *
0936:             * @return  returns true if scan has been repositioned successfully, else
0937:             *          returns false if the position key could not be found and
0938:             *          missing_row_for_key_ok was false indicating that scan could
0939:             *          only be positioned on the exact key match.
0940:             *
0941:             * @exception  StandardException  Standard exception policy.
0942:             **/
0943:            protected boolean reposition(BTreeRowPosition pos,
0944:                    boolean missing_row_for_key_ok) throws StandardException {
0945:                // RESOLVE (mikem) - performance - we need to do a buffer manager
0946:                // get for every row returned from the scan.  It may be better to
0947:                // allow a reference to the page with no latch (ie. a fixed bit).
0948:
0949:                if (this .scan_state != SCAN_INPROGRESS) {
0950:                    throw StandardException.newException(
0951:                            SQLState.BTREE_SCAN_NOT_POSITIONED, new Integer(
0952:                                    this .scan_state));
0953:                }
0954:
0955:                // Either current_rh or positionKey is valid - the other is null.
0956:                if (SanityManager.DEBUG) {
0957:                    if ((pos.current_rh == null) != (pos.current_positionKey != null))
0958:                        SanityManager.THROWASSERT("pos.current_rh  = ("
0959:                                + pos.current_rh + "), "
0960:                                + "pos.current_positionKey = ("
0961:                                + pos.current_positionKey + ").");
0962:                }
0963:
0964:                if (!((pos.current_rh == null) == (pos.current_positionKey != null))) {
0965:                    throw StandardException.newException(
0966:                            SQLState.BTREE_SCAN_INTERNAL_ERROR, new Boolean(
0967:                                    pos.current_rh == null), new Boolean(
0968:                                    pos.current_positionKey == null));
0969:                }
0970:
0971:                if (pos.current_positionKey == null) {
0972:                    // Reposition to remembered spot on page.
0973:                    if (SanityManager.DEBUG)
0974:                        SanityManager.ASSERT(pos.current_scan_pageno != 0);
0975:
0976:                    pos.current_leaf = (LeafControlRow) ControlRow.Get(this ,
0977:                            pos.current_rh.getPageNumber());
0978:                    pos.current_slot = pos.current_leaf.page
0979:                            .getSlotNumber(pos.current_rh);
0980:                } else {
0981:                    // RESOLVE (mikem) - not sure but someday in the future this
0982:                    // assert may not be true, but for now we always release the 
0983:                    // scan lock when we save the row away as the current position.
0984:                    if (SanityManager.DEBUG)
0985:                        SanityManager.ASSERT(pos.current_scan_pageno == 0);
0986:
0987:                    SearchParameters sp = new SearchParameters(
0988:                            pos.current_positionKey,
0989:                            // this is a full key search, so this arg is not used.
0990:                            SearchParameters.POSITION_LEFT_OF_PARTIAL_KEY_MATCH,
0991:                            init_template, this , false);
0992:
0993:                    // latch/lock loop, continue until you can get scan lock on page
0994:                    // while holding page latched without waiting.
0995:
0996:                    boolean latch_released;
0997:                    do {
0998:                        pos.current_leaf = (LeafControlRow) ControlRow.Get(
0999:                                this , BTree.ROOTPAGEID).search(sp);
1000:
1001:                        if (sp.resultExact || missing_row_for_key_ok) {
1002:                            // RESOLVE (mikem) - we could have a scan which always 
1003:                            // maintained it's position by key value, or we could 
1004:                            // optimize and delay this lock until we were about to 
1005:                            // give up the latch.  But it is VERY likely we will get 
1006:                            // the lock since we have the latch on the page.
1007:                            //
1008:                            // In order to be successfully positioned we must get the 
1009:                            // scan lock again.
1010:                            latch_released = !this .getLockingPolicy().lockScan(
1011:                                    pos.current_leaf,
1012:                                    (LeafControlRow) null, // no other latch currently
1013:                                    false /* not for update */,
1014:                                    ConglomerateController.LOCK_READ); // read lock on scan position
1015:
1016:                            // TESTING CODE:
1017:                            if (SanityManager.DEBUG) {
1018:                                latch_released = test_errors(this ,
1019:                                        "BTreeScan_reposition", true, this 
1020:                                                .getLockingPolicy(),
1021:                                        pos.current_leaf, latch_released);
1022:                            }
1023:                        } else {
1024:                            // Did not find key to exactly position on.
1025:
1026:                            pos.current_leaf.release();
1027:                            pos.current_leaf = null;
1028:                            return (false);
1029:                        }
1030:
1031:                    } while (latch_released);
1032:
1033:                    pos.current_scan_pageno = pos.current_leaf.page
1034:                            .getPageNumber();
1035:                    pos.current_slot = sp.resultSlot;
1036:                    pos.current_positionKey = null;
1037:                }
1038:
1039:                return (true);
1040:            }
1041:
1042:            /*
1043:             ** Public Methods of BTreeScan
1044:             */
1045:
1046:            /**
1047:            Initialize the scan for use.
1048:            <p>
1049:            Any changes to this method may have to be reflected in close as well.
1050:            <p>
1051:            The btree init opens the container (super.init), and stores away the
1052:            state of the qualifiers.  The actual searching for the first position
1053:            is delayed until the first next() call.
1054:
1055:            @exception  StandardException  Standard exception policy.
1056:             **/
1057:            public void init(TransactionManager xact_manager,
1058:                    Transaction rawtran, boolean hold, int open_mode,
1059:                    int lock_level, BTreeLockingPolicy btree_locking_policy,
1060:                    FormatableBitSet scanColumnList,
1061:                    DataValueDescriptor[] startKeyValue,
1062:                    int startSearchOperator, Qualifier qualifier[][],
1063:                    DataValueDescriptor[] stopKeyValue, int stopSearchOperator,
1064:                    BTree conglomerate, LogicalUndo undo,
1065:                    StaticCompiledOpenConglomInfo static_info,
1066:                    DynamicCompiledOpenConglomInfo dynamic_info)
1067:                    throws StandardException {
1068:                super .init(xact_manager, xact_manager, (ContainerHandle) null,
1069:                        rawtran, hold, open_mode, lock_level,
1070:                        btree_locking_policy, conglomerate, undo, dynamic_info);
1071:
1072:                this .init_rawtran = rawtran;
1073:                this .init_forUpdate = ((open_mode & ContainerHandle.MODE_FORUPDATE) == ContainerHandle.MODE_FORUPDATE);
1074:
1075:                // Keep track of whether this scan should use update locks.
1076:                this .init_useUpdateLocks = ((open_mode & ContainerHandle.MODE_USE_UPDATE_LOCKS) != 0);
1077:
1078:                this .init_hold = hold;
1079:
1080:                this .init_template = runtime_mem.get_template();
1081:
1082:                this .init_scanColumnList = scanColumnList;
1083:
1084:                this .init_lock_fetch_desc = RowUtil
1085:                        .getFetchDescriptorConstant(init_template.length - 1);
1086:
1087:                if (SanityManager.DEBUG) {
1088:                    SanityManager
1089:                            .ASSERT(init_lock_fetch_desc.getMaxFetchColumnId() == (init_template.length - 1));
1090:                    SanityManager
1091:                            .ASSERT((init_lock_fetch_desc
1092:                                    .getValidColumnsArray())[init_template.length - 1] == 1);
1093:                }
1094:
1095:                // note that we don't process qualifiers in btree fetch's
1096:                this .init_fetchDesc = new FetchDescriptor(init_template.length,
1097:                        init_scanColumnList, (Qualifier[][]) null);
1098:
1099:                initScanParams(startKeyValue, startSearchOperator, qualifier,
1100:                        stopKeyValue, stopSearchOperator);
1101:
1102:                if (SanityManager.DEBUG) {
1103:                    // RESOLVE - (mikem) we should we require a template, need to 
1104:                    // clean up some of the old tests which did not provide one?
1105:                    if (init_template != null) {
1106:                        SanityManager.ASSERT(TemplateRow.checkColumnTypes(this 
1107:                                .getConglomerate().format_ids, init_template));
1108:                    }
1109:                }
1110:
1111:                // System.out.println("initializing scan:" + this);
1112:
1113:                // initialize default locking operation for the scan.
1114:                this .lock_operation = (init_forUpdate ? ConglomerateController.LOCK_UPD
1115:                        : ConglomerateController.LOCK_READ);
1116:
1117:                if (init_useUpdateLocks)
1118:                    this .lock_operation |= ConglomerateController.LOCK_UPDATE_LOCKS;
1119:
1120:                // System.out.println("Btree scan: " + this);
1121:            }
1122:
1123:            /*
1124:             ** Methods of ScanController
1125:             */
1126:
1127:            /**
1128:            Close the scan.
1129:             **/
1130:            public void close() throws StandardException {
1131:                // Scan is closed, make sure no access to any state variables
1132:                positionAtDoneScanFromClose(scan_position);
1133:
1134:                super .close();
1135:
1136:                // null out so that these object's can get GC'd earlier.
1137:                this .init_rawtran = null;
1138:                this .init_template = null;
1139:                this .init_startKeyValue = null;
1140:                this .init_qualifier = null;
1141:                this .init_stopKeyValue = null;
1142:
1143:                this .getXactMgr().closeMe(this );
1144:            }
1145:
1146:            /**
1147:            Delete the row at the current position of the scan.
1148:            @see ScanController#delete
1149:
1150:            @exception  StandardException  Standard exception policy.
1151:             **/
1152:            public boolean delete() throws StandardException {
1153:                boolean ret_val = false;
1154:
1155:                if (scan_state != SCAN_INPROGRESS)
1156:                    throw StandardException
1157:                            .newException(SQLState.AM_SCAN_NOT_POSITIONED);
1158:
1159:                if (SanityManager.DEBUG) {
1160:                    SanityManager.ASSERT(this .container != null,
1161:                            "BTreeScan.delete() called on a closed scan.");
1162:                    SanityManager.ASSERT(init_forUpdate);
1163:                }
1164:
1165:                try {
1166:                    // Get current page of scan, with latch.
1167:                    if (!reposition(scan_position, false)) {
1168:                        throw StandardException.newException(
1169:                                SQLState.AM_RECORD_NOT_FOUND, new Long(
1170:                                        err_containerid), new Long(
1171:                                        scan_position.current_rh.getId()));
1172:                    }
1173:
1174:                    if (init_useUpdateLocks) {
1175:                        // RESOLVE (mikem) - I don't think lockScanRow() is the right
1176:                        // thing to call.
1177:
1178:                        // if we are doing update locking, then we got an U lock on
1179:                        // this row when the scan positioned on it, but now that we
1180:                        // are doing a delete on the current position we need to upgrade
1181:                        // the lock to X.
1182:                        boolean latch_released = !this .getLockingPolicy()
1183:                                .lockScanRow(this , this .getConglomerate(),
1184:                                        scan_position, false,
1185:                                        init_lock_fetch_desc,
1186:                                        scan_position.current_lock_template,
1187:                                        scan_position.current_lock_row_loc,
1188:                                        false, init_forUpdate, lock_operation);
1189:
1190:                        if (latch_released) {
1191:                            // lost latch on page in order to wait for row lock.
1192:                            // Because we have scan lock on page, we need only
1193:                            // call reposition() which will use the saved record
1194:                            // handle to reposition to the same spot on the page.
1195:                            // We don't have to search the
1196:                            // tree again, as we have the a scan lock on the page
1197:                            // which means the current_rh is valid to reposition on.
1198:                            if (reposition(scan_position, false)) {
1199:                                throw StandardException.newException(
1200:                                        SQLState.AM_RECORD_NOT_FOUND, new Long(
1201:                                                err_containerid), new Long(
1202:                                                scan_position.current_rh
1203:                                                        .getId()));
1204:                            }
1205:                        }
1206:                    }
1207:
1208:                    // Do a fetch just to get the RecordHandle for the delete call,
1209:                    // don't fetch any columns.
1210:                    RecordHandle delete_rh = scan_position.current_leaf.page
1211:                            .fetchFromSlot((RecordHandle) null,
1212:                                    scan_position.current_slot,
1213:                                    RowUtil.EMPTY_ROW, (FetchDescriptor) null,
1214:                                    true);
1215:
1216:                    ret_val = scan_position.current_leaf.page.delete(delete_rh,
1217:                            this .btree_undo);
1218:
1219:                    // See if we just deleted the last row on the page, in a btree a
1220:                    // page with all rows still has 1 left - the control row.
1221:                    // Beetle 5750: we do not reclaim the root page of the btree if 
1222:                    // there are no children since we were
1223:                    // doing too many post commit actions in a benchmark which does an
1224:                    // insert/commit/delete/commit operations in a single user system. now ,
1225:                    // with this change the work will move to the user
1226:                    // thread which does the insert 
1227:
1228:                    if (scan_position.current_leaf.page.nonDeletedRecordCount() == 1
1229:                            && !(scan_position.current_leaf.getIsRoot() && scan_position.current_leaf
1230:                                    .getLevel() == 0)) {
1231:                        this .getXactMgr().addPostCommitWork(
1232:                                new BTreePostCommit(this .getXactMgr()
1233:                                        .getAccessManager(), this 
1234:                                        .getConglomerate(),
1235:                                        scan_position.current_leaf.page
1236:                                                .getPageNumber()));
1237:                    }
1238:                } finally {
1239:                    if (scan_position.current_leaf != null) {
1240:                        // release latch on page
1241:                        scan_position.current_leaf.release();
1242:                        scan_position.current_leaf = null;
1243:                    }
1244:                }
1245:
1246:                return (ret_val);
1247:            }
1248:
1249:            /**
1250:             * A call to allow client to indicate that current row does not qualify.
1251:             * <p>
1252:             * Indicates to the ScanController that the current row does not
1253:             * qualify for the scan.  If the isolation level of the scan allows, 
1254:             * this may result in the scan releasing the lock on this row.
1255:             * <p>
1256:             * Note that some scan implimentations may not support releasing locks on 
1257:             * non-qualifying rows, or may delay releasing the lock until sometime
1258:             * later in the scan (ie. it may be necessary to keep the lock until 
1259:             * either the scan is repositioned on the next row or page).
1260:             * <p>
1261:             * This call should only be made while the scan is positioned on a current
1262:             * valid row.
1263:             *
1264:             * @exception  StandardException  Standard exception policy.
1265:             **/
1266:            public void didNotQualify() throws StandardException {
1267:            }
1268:
1269:            /**
1270:             * Returns true if the current position of the scan still qualifies
1271:             * under the set of qualifiers passed to the openScan().  When called
1272:             * this routine will reapply all qualifiers against the row currently
1273:             * positioned and return true if the row still qualifies.  If the row
1274:             * has been deleted or no longer passes the qualifiers then this routine
1275:             * will return false.
1276:             * <p>
1277:             * This case can come about if the current scan
1278:             * or another scan on the same table in the same transaction
1279:             * deleted the row or changed columns referenced by the qualifier after
1280:             * the next() call which positioned the scan at this row.
1281:             * <p>
1282:             * Note that for comglomerates which don't support update, like btree's,
1283:             * there is no need to recheck the qualifiers.
1284:             * <p>
1285:             * The results of a fetch() performed on a scan positioned on
1286:             * a deleted row are undefined.
1287:             * <p>
1288:             * @exception StandardException Standard exception policy.
1289:             **/
1290:            public boolean doesCurrentPositionQualify()
1291:                    throws StandardException {
1292:                if (scan_state != SCAN_INPROGRESS)
1293:                    throw StandardException
1294:                            .newException(SQLState.AM_SCAN_NOT_POSITIONED);
1295:
1296:                if (SanityManager.DEBUG) {
1297:                    SanityManager
1298:                            .ASSERT(this .container != null,
1299:                                    "BTreeScan.doesCurrentPositionQualify() called on a closed scan.");
1300:                }
1301:
1302:                try {
1303:                    // Get current page of scan, with latch
1304:                    if (!reposition(scan_position, false)) {
1305:                        // TODO - write unit test to get here, language always calls
1306:                        // isCurrentPositionDeleted() right before calling this, so
1307:                        // hard to write .sql test to exercise this.
1308:
1309:                        // if reposition fails it means the position of the scan
1310:                        // has been purged from the table - for example if this is
1311:                        // a uncommitted read scan and somehow the row was purged 
1312:                        // since the last positioning.
1313:
1314:                        return (false);
1315:                    }
1316:
1317:                    if (SanityManager.DEBUG) {
1318:                        SanityManager
1319:                                .ASSERT(scan_position.current_leaf.page
1320:                                        .fetchNumFieldsAtSlot(scan_position.current_slot) > 1);
1321:                    }
1322:
1323:                    // Since btree row don't get updated, the only way a current
1324:                    // position may not qualify is if it got deleted.
1325:                    return (!scan_position.current_leaf.page
1326:                            .isDeletedAtSlot(scan_position.current_slot));
1327:                } finally {
1328:
1329:                    if (scan_position.current_leaf != null) {
1330:                        // release latch on page.
1331:                        scan_position.current_leaf.release();
1332:                        scan_position.current_leaf = null;
1333:                    }
1334:                }
1335:            }
1336:
1337:            /**
1338:             * Fetch the row at the current position of the Scan.
1339:             * 
1340:             * @param row The row into which the value of the current 
1341:             * position in the scan is to be stored.
1342:             * @param qualify indicates whether the qualifiers should be applied.
1343:             * 
1344:             * @exception  StandardException  Standard exception policy.
1345:             */
1346:            private void fetch(DataValueDescriptor[] row, boolean qualify)
1347:                    throws StandardException {
1348:                if (scan_state != SCAN_INPROGRESS)
1349:                    throw StandardException
1350:                            .newException(SQLState.AM_SCAN_NOT_POSITIONED);
1351:                if (SanityManager.DEBUG) {
1352:                    SanityManager.ASSERT(this .container != null,
1353:                            "BTreeScan.fetch() called on a closed scan.");
1354:
1355:                    TemplateRow.checkPartialColumnTypes(
1356:                            this .getConglomerate().format_ids,
1357:                            init_scanColumnList, (int[]) null, row);
1358:                }
1359:
1360:                try {
1361:                    // Get current page of scan, with latch
1362:                    if (!reposition(scan_position, false)) {
1363:                        // TODO - write unit test to get here, language always calls
1364:                        // isCurrentPositionDeleted() right before calling this, so
1365:                        // hard to write .sql test to exercise this.
1366:
1367:                        throw StandardException.newException(
1368:                                SQLState.AM_RECORD_NOT_FOUND, new Long(
1369:                                        err_containerid), new Long(
1370:                                        scan_position.current_rh.getId()));
1371:                    }
1372:
1373:                    if (SanityManager.DEBUG) {
1374:                        SanityManager
1375:                                .ASSERT(scan_position.current_leaf.page
1376:                                        .fetchNumFieldsAtSlot(scan_position.current_slot) > 1);
1377:                    }
1378:
1379:                    scan_position.current_rh = scan_position.current_leaf.page
1380:                            .fetchFromSlot((RecordHandle) null,
1381:                                    scan_position.current_slot, row,
1382:                                    qualify ? init_fetchDesc : null, true);
1383:
1384:                    // The possibility is that the row at the current position
1385:                    // has been marked as deleted (it cannot have been purged
1386:                    // since the scan maintains a lock on the row, and purges
1387:                    // are always done from system transactions).  I'm not sure
1388:                    // what the desired behavior is in this case.  For now,
1389:                    // just return null.
1390:
1391:                    // RESOLVE (mikem) - what should be done here?
1392:                    if (scan_position.current_leaf.page
1393:                            .isDeletedAtSlot(scan_position.current_slot)) {
1394:                        if (SanityManager.DEBUG)
1395:                            SanityManager.ASSERT(false,
1396:                                    "positioned on deleted row");
1397:                    }
1398:                } finally {
1399:                    if (scan_position.current_leaf != null) {
1400:                        // release latch on page.
1401:                        scan_position.current_leaf.release();
1402:                        scan_position.current_leaf = null;
1403:                    }
1404:                }
1405:
1406:                return;
1407:            }
1408:
1409:            /**
1410:            Fetch the row at the current position of the Scan.
1411:            @see ScanController#fetch
1412:
1413:            @exception  StandardException  Standard exception policy.
1414:             **/
1415:            public void fetch(DataValueDescriptor[] row)
1416:                    throws StandardException {
1417:                fetch(row, true);
1418:            }
1419:
1420:            /**
1421:             * Fetch the row at the current position of the Scan without applying the 
1422:             * qualifiers.
1423:             * @see ScanController#fetchWithoutQualify
1424:             * 
1425:             * @exception  StandardException  Standard exception policy.
1426:             */
1427:            public void fetchWithoutQualify(DataValueDescriptor[] row)
1428:                    throws StandardException {
1429:                fetch(row, false);
1430:            }
1431:
1432:            /**
1433:             * Return ScanInfo object which describes performance of scan.
1434:             * <p>
1435:             * Return ScanInfo object which contains information about the current
1436:             * scan.
1437:             * <p>
1438:             *
1439:             * @see ScanInfo
1440:             *
1441:             * @return The ScanInfo object which contains info about current scan.
1442:             *
1443:             * @exception  StandardException  Standard exception policy.
1444:             **/
1445:            public ScanInfo getScanInfo() throws StandardException {
1446:                return (new BTreeScanInfo(this ));
1447:            }
1448:
1449:            /**
1450:            Returns true if the current position of the scan is at a
1451:            deleted row.  This case can come about if the current scan
1452:            or another scan on the same table in the same transaction
1453:            deleted the row after the next() call which positioned the
1454:            scan at this row.
1455:
1456:            The results of a fetch() performed on a scan positioned on
1457:            a deleted row are undefined.
1458:
1459:            @exception StandardException Standard exception policy.
1460:             **/
1461:            public boolean isCurrentPositionDeleted() throws StandardException {
1462:                boolean ret_val;
1463:
1464:                if (scan_state != SCAN_INPROGRESS)
1465:                    throw StandardException
1466:                            .newException(SQLState.AM_SCAN_NOT_POSITIONED);
1467:
1468:                if (SanityManager.DEBUG) {
1469:                    SanityManager
1470:                            .ASSERT(this .container != null,
1471:                                    "BTreeScan.isCurrentPositionDeleted() called on closed scan.");
1472:                }
1473:                try {
1474:                    // Get current page of scan, with latch
1475:
1476:                    if (reposition(scan_position, false)) {
1477:
1478:                        if (SanityManager.DEBUG) {
1479:                            SanityManager
1480:                                    .ASSERT(scan_position.current_leaf.page
1481:                                            .fetchNumFieldsAtSlot(scan_position.current_slot) > 1);
1482:                        }
1483:
1484:                        ret_val = scan_position.current_leaf.page
1485:                                .isDeletedAtSlot(scan_position.current_slot);
1486:                    } else {
1487:                        ret_val = false;
1488:                    }
1489:                } finally {
1490:                    if (scan_position.current_leaf != null) {
1491:                        // release latch on page.
1492:                        scan_position.current_leaf.release();
1493:                        scan_position.current_leaf = null;
1494:                    }
1495:                }
1496:
1497:                return (ret_val);
1498:            }
1499:
1500:            /**
1501:             * Return whether this is a keyed conglomerate.
1502:             * <p>
1503:             *
1504:             * @return whether this is a keyed conglomerate.
1505:             **/
1506:            public boolean isKeyed() {
1507:                return (true);
1508:            }
1509:
1510:            /**
1511:             * @see ScanController#positionAtRowLocation
1512:             *
1513:             * Not implemented for this class
1514:             */
1515:            public boolean positionAtRowLocation(RowLocation rLoc)
1516:                    throws StandardException {
1517:                throw StandardException
1518:                        .newException(SQLState.BTREE_UNIMPLEMENTED_FEATURE);
1519:            }
1520:
1521:            /**
1522:            Move to the next position in the scan.
1523:            @see ScanController#next
1524:
1525:            @exception  StandardException  Standard exception policy.
1526:             **/
1527:            public boolean next() throws StandardException {
1528:                // Turn this call into a group fetch of a 1 element group.
1529:                fetchNext_one_slot_array[0] = runtime_mem.get_scratch_row();
1530:                boolean ret_val = fetchRows(scan_position,
1531:                        fetchNext_one_slot_array, (RowLocation[]) null,
1532:                        (BackingStoreHashtable) null, 1, (int[]) null) == 1;
1533:
1534:                return (ret_val);
1535:            }
1536:
1537:            /**
1538:            Fetch the row at the next position of the Scan.
1539:
1540:            If there is a valid next position in the scan then
1541:            the value in the template storable row is replaced
1542:            with the value of the row at the current scan
1543:            position.  The columns of the template row must
1544:            be of the same type as the actual columns in the
1545:            underlying conglomerate.
1546:
1547:            The resulting contents of templateRow after a fetchNext() 
1548:            which returns false is undefined.
1549:
1550:            The result of calling fetchNext(row) is exactly logically
1551:            equivalent to making a next() call followed by a fetch(row)
1552:            call.  This interface allows implementations to optimize 
1553:            the 2 calls if possible.
1554:
1555:            @param row The template row into which the value
1556:            of the next position in the scan is to be stored.
1557:
1558:            @return True if there is a next position in the scan,
1559:            false if there isn't.
1560:
1561:            @exception StandardException Standard exception policy.
1562:             **/
1563:            public boolean fetchNext(DataValueDescriptor[] row)
1564:                    throws StandardException {
1565:                boolean ret_val;
1566:
1567:                if (SanityManager.DEBUG) {
1568:                    TemplateRow.checkPartialColumnTypes(
1569:                            this .getConglomerate().format_ids,
1570:                            init_scanColumnList, (int[]) null, row);
1571:                }
1572:
1573:                // Turn this call into a group fetch of a 1 element group.
1574:                fetchNext_one_slot_array[0] = row;
1575:                ret_val = fetchRows(scan_position, fetchNext_one_slot_array,
1576:                        (RowLocation[]) null, (BackingStoreHashtable) null, 1,
1577:                        (int[]) null) == 1;
1578:
1579:                return (ret_val);
1580:            }
1581:
1582:            /**
1583:             * Fetch the next N rows from the table.
1584:             * <p>
1585:             * The client allocates an array of N rows and passes it into the
1586:             * fetchNextSet() call.  This routine does the equivalent of N 
1587:             * fetchNext() calls, filling in each of the rows in the array.
1588:             * Locking is performed exactly as if the N fetchNext() calls had
1589:             * been made.
1590:             * <p>
1591:             * It is up to Access how many rows to return.  fetchNextSet() will
1592:             * return how many rows were filled in.  If fetchNextSet() returns 0
1593:             * then the scan is complete, (ie. the scan is in the same state as if
1594:             * fetchNext() had returned false).  If the scan is not complete then
1595:             * fetchNext() will return (1 <= row_count <= N).
1596:             * <p>
1597:             * The current position of the scan is undefined if fetchNextSet()
1598:             * is used (ie. mixing fetch()/fetchNext() and fetchNextSet() calls
1599:             * in a single scan does not work).  This is because a fetchNextSet()
1600:             * request for 5 rows from a heap where the first 2 rows qualify, but
1601:             * no other rows qualify will result in the scan being positioned at
1602:             * the end of the table, while if 5 rows did qualify the scan will be
1603:             * positioned on the 5th row.
1604:             * <p>
1605:             * Qualifiers, start and stop positioning of the openscan are applied
1606:             * just as in a normal scan. 
1607:             * <p>
1608:             * The columns of the row will be the standard columns returned as
1609:             * part of a scan, as described by the validColumns - see openScan for
1610:             * description.
1611:             * <p>
1612:             * Expected usage:
1613:             *
1614:             * // allocate an array of 5 empty row templates
1615:             * DataValueDescriptor[][] row_array = allocate_row_array(5);
1616:             * int row_cnt = 0;
1617:             *
1618:             * scan = openScan();
1619:             *
1620:             * while ((row_cnt = scan.fetchNextSet(row_array) != 0)
1621:             * {
1622:             *     // I got "row_cnt" rows from the scan.  These rows will be
1623:             *     // found in row_array[0] through row_array[row_cnt - 1]
1624:             * }
1625:             *
1626:             * <p>
1627:             *
1628:             * RESOLVE - This interface is being provided so that we can prototype
1629:             *           the performance results it can achieve.  If it looks like
1630:             *           this interface is useful, it is very likely we will look
1631:             *           into a better way to tie together the now 4 different
1632:             *           fetch interfaces: fetch, fetchNext(), fetchNextGroup(),
1633:             *           and fetchSet().
1634:             *
1635:             * @return The number of qualifying rows found and copied into the 
1636:             *         provided array of rows.  If 0 then the scan is complete, 
1637:             *         otherwise the return value will be: 
1638:             *         1 <= row_count <= row_array.length
1639:             *
1640:             * @param row_array         The array of rows to copy rows into.  
1641:             *                          row_array[].length must >= 1.  This routine
1642:             *                          assumes that all entries in the array 
1643:             *                          contain complete template rows.
1644:             *
1645:             * @exception  StandardException  Standard exception policy.
1646:             **/
1647:            public int fetchNextGroup(DataValueDescriptor[][] row_array,
1648:                    RowLocation[] rowloc_array) throws StandardException {
1649:                return (fetchRows(scan_position, row_array, rowloc_array,
1650:                        (BackingStoreHashtable) null, row_array.length,
1651:                        (int[]) null));
1652:            }
1653:
1654:            public int fetchNextGroup(DataValueDescriptor[][] row_array,
1655:                    RowLocation[] old_rowloc_array,
1656:                    RowLocation[] new_rowloc_array) throws StandardException {
1657:                // This interface is currently only used to move rows around in
1658:                // a heap table, unused in btree's -- so not implemented.
1659:
1660:                throw StandardException
1661:                        .newException(SQLState.BTREE_UNIMPLEMENTED_FEATURE);
1662:            }
1663:
1664:            /**
1665:             * Insert all rows that qualify for the current scan into the input
1666:             * Hash table.  
1667:             * <p>
1668:             * This routine scans executes the entire scan as described in the 
1669:             * openScan call.  For every qualifying unique row value an entry is
1670:             * placed into the HashTable. For unique row values the entry in the
1671:             * BackingStoreHashtable has a key value of the object stored in 
1672:             * row[key_column_number], and the value of the data is row.  For row 
1673:             * values with duplicates, the key value is also row[key_column_number], 
1674:             * but the value of the data is a Vector of
1675:             * rows.  The caller will have to call "instanceof" on the data value
1676:             * object if duplicates are expected, to determine if the data value
1677:             * of the Hashtable entry is a row or is a Vector of rows.
1678:             * <p>
1679:             * Note, that for this routine to work efficiently the caller must 
1680:             * ensure that the object in row[key_column_number] implements 
1681:             * the hashCode and equals method as appropriate for it's datatype.
1682:             * <p>
1683:             * It is expected that this call will be the first and only call made in
1684:             * an openscan.  Qualifiers and stop position of the openscan are applied
1685:             * just as in a normal scan.  This call is logically equivalent to the 
1686:             * caller performing the following:
1687:             *
1688:             * import java.util.Hashtable;
1689:             *
1690:             * hash_table = new Hashtable();
1691:             *
1692:             * while (next())
1693:             * {
1694:             *     row = create_new_row();
1695:             *     fetch(row);
1696:             *     if ((duplicate_value = 
1697:             *         hash_table.put(row[key_column_number], row)) != null)
1698:             *     {
1699:             *         Vector row_vec;
1700:             *
1701:             *         // inserted a duplicate
1702:             *         if ((duplicate_value instanceof vector))
1703:             *         {
1704:             *             row_vec = (Vector) duplicate_value;
1705:             *         }
1706:             *         else
1707:             *         {
1708:             *             // allocate vector to hold duplicates
1709:             *             row_vec = new Vector(2);
1710:             *
1711:             *             // insert original row into vector
1712:             *             row_vec.addElement(duplicate_value);
1713:             *
1714:             *             // put the vector as the data rather than the row
1715:             *             hash_table.put(row[key_column_number], row_vec);
1716:             *         }
1717:             *         
1718:             *         // insert new row into vector
1719:             *         row_vec.addElement(row);
1720:             *     }
1721:             * }
1722:             * <p>
1723:             * The columns of the row will be the standard columns returned as
1724:             * part of a scan, as described by the validColumns - see openScan for
1725:             * description.
1726:             * RESOLVE - is this ok?  or should I hard code somehow the row to
1727:             *           be the first column and the row location?
1728:             * <p>
1729:             * Currently it is only possible to hash on the first column in the
1730:             * conglomerate, in the future we may change the interface to allow
1731:             * hashing either on a different column or maybe on a combination of
1732:             * columns.
1733:             * <p>
1734:             * No overflow to external storage is provided, so calling this routine
1735:             * on a 1 gigabyte conglomerate will incur at least 1 gigabyte of memory
1736:             * (probably failing with a java out of memory condition).  If this
1737:             * routine gets an out of memory condition, or if "max_rowcnt" is 
1738:             * exceeded then then the routine will give up, empty the Hashtable, 
1739:             * and return "false."
1740:             * <p>
1741:             * On exit from this routine, whether the fetchSet() succeeded or not
1742:             * the scan is complete, it is positioned just the same as if the scan
1743:             * had been drained by calling "next()" until it returns false (ie. 
1744:             * fetchNext() and next() calls will return false).  
1745:             * reopenScan() can be called to restart the scan.
1746:             * <p>
1747:             *
1748:             * RESOLVE - until we get row counts what should we do for sizing the
1749:             *           the size, capasity, and load factor of the hash table.
1750:             *           For now it is up to the caller to create the Hashtable,
1751:             *           Access does not reset any parameters.
1752:             * <p>
1753:             * RESOLVE - I am not sure if access should be in charge of allocating
1754:             *           the new row objects.  I know that I can do this in the
1755:             *           case of btree's, but I don't think I can do this in heaps.
1756:             *           Maybe this is solved by work to be done on the sort 
1757:             *           interface.
1758:             *
1759:             *
1760:             * @param max_rowcnt        The maximum number of rows to insert into the 
1761:             *                          Hash table.  Pass in -1 if there is no maximum.
1762:             * @param key_column_numbers The column numbers of the columns in the
1763:             *                          scan result row to be the key to the Hashtable.
1764:             *                          "0" is the first column in the scan result
1765:             *                          row (which may be different than the first
1766:             *                          column in the row in the table of the scan).
1767:             * @param hash_table        The java HashTable to load into.
1768:             *
1769:             * @exception  StandardException  Standard exception policy.
1770:             **/
1771:            public void fetchSet(long max_rowcnt, int[] key_column_numbers,
1772:                    BackingStoreHashtable hash_table) throws StandardException {
1773:                // System.out.println("fetchSet");
1774:
1775:                fetchRows(scan_position, (DataValueDescriptor[][]) null,
1776:                        (RowLocation[]) null,
1777:                        (BackingStoreHashtable) hash_table, max_rowcnt,
1778:                        key_column_numbers);
1779:
1780:                return;
1781:            }
1782:
1783:            /**
1784:            Reposition the current scan.  This call is semantically the same as if
1785:            the current scan had been closed and a openScan() had been called instead.
1786:            The scan is reopened with against the same conglomerate, and the scan
1787:            is reopened with the same "hold" and "forUpdate" parameters passed in
1788:            the original openScan.  The previous template row continues to be used.
1789:
1790:            @param startKeyValue  An indexable row which holds a
1791:            (partial) key value which, in combination with the
1792:            startSearchOperator, defines the starting position of
1793:            the scan.  If null, the starting position of the scan
1794:            is the first row of the conglomerate.
1795:
1796:            @param startSearchOperator an operator which defines
1797:            how the startKeyValue is to be searched for.  If
1798:            startSearchOperation is ScanController.GE, the scan starts on
1799:            the first row which is greater than or equal to the
1800:            startKeyValue.  If startSearchOperation is ScanController.GT,
1801:            the scan starts on the first row whose key is greater than
1802:            startKeyValue.  The startSearchOperation parameter is
1803:            ignored if the startKeyValue parameter is null.
1804:
1805:            @param qualifier An array of qualifiers which, applied
1806:            to each key, restrict the rows returned by the scan.  Rows
1807:            for which any one of the qualifiers returns false are not
1808:            returned by the scan. If null, all rows are returned.
1809:
1810:            @param stopKeyValue  An indexable row which holds a
1811:            (partial) key value which, in combination with the
1812:            stopSearchOperator, defines the ending position of
1813:            the scan.  If null, the ending position of the scan
1814:            is the last row of the conglomerate.
1815:
1816:            @param stopSearchOperator an operator which defines
1817:            how the stopKeyValue is used to determine the scan stopping
1818:            position. If stopSearchOperation is ScanController.GE, the scan
1819:            stops just before the first row which is greater than or
1820:            equal to the stopKeyValue.  If stopSearchOperation is
1821:            ScanController.GT, the scan stops just before the first row whose
1822:            key is greater than	startKeyValue.  The stopSearchOperation
1823:            parameter is ignored if the stopKeyValue parameter is null.
1824:
1825:            @exception StandardException Standard exception policy.
1826:             **/
1827:            public final void reopenScan(DataValueDescriptor[] startKeyValue,
1828:                    int startSearchOperator, Qualifier qualifier[][],
1829:                    DataValueDescriptor[] stopKeyValue, int stopSearchOperator)
1830:                    throws StandardException {
1831:                if (SanityManager.DEBUG) {
1832:                    if (!init_hold)
1833:                        SanityManager
1834:                                .ASSERT(this .container != null,
1835:                                        "BTreeScan.reopenScan() called on non-held closed scan.");
1836:
1837:                    // should only be called by clients outside of store, so should
1838:                    // not be possible for a latch to held.
1839:                    SanityManager.ASSERT(scan_position.current_leaf == null);
1840:                }
1841:
1842:                // call unlockScanRecordAfterRead() before setting the scan back
1843:                // to init state, so that we release the last lock if necessary (ie.
1844:                // for read committed).
1845:                //
1846:
1847:                if (scan_position.current_rh != null) {
1848:                    // reposition to get record handle if we don't have it.
1849:
1850:                    if (!reposition(scan_position, false)) {
1851:                        if (SanityManager.DEBUG) {
1852:                            SanityManager
1853:                                    .THROWASSERT("can not fail while holding update row lock.");
1854:                        }
1855:                    }
1856:
1857:                    this .getLockingPolicy().unlockScanRecordAfterRead(
1858:                            scan_position, init_forUpdate);
1859:
1860:                    scan_position.current_rh = null;
1861:                    scan_position.current_leaf.release();
1862:                    scan_position.current_leaf = null;
1863:                }
1864:
1865:                // Need to do this unlock in any case, until lock manager provides
1866:                // a way to release locks associated with a compatibility space.  This
1867:                // scan lock is special, as it is a lock on the btree container rather
1868:                // than the heap container.  The open container on the btree actually
1869:                // has a null locking policy so the close of that container does not
1870:                // release this lock, need to explicitly unlock it here or when the
1871:                // scan is closed as part of the abort the lock will not be released.
1872:                if (scan_position.current_scan_pageno != 0) {
1873:                    this .getLockingPolicy().unlockScan(
1874:                            scan_position.current_scan_pageno);
1875:                    scan_position.current_scan_pageno = 0;
1876:                }
1877:
1878:                scan_position.current_slot = Page.INVALID_SLOT_NUMBER;
1879:                scan_position.current_rh = null;
1880:                scan_position.current_positionKey = null;
1881:
1882:                initScanParams(startKeyValue, startSearchOperator, qualifier,
1883:                        stopKeyValue, stopSearchOperator);
1884:
1885:                if (!init_hold)
1886:                    this .scan_state = SCAN_INIT;
1887:                else
1888:                    this .scan_state = (this .container != null ? SCAN_INIT
1889:                            : SCAN_HOLD_INIT);
1890:            }
1891:
1892:            /**
1893:            Reposition the current scan.  This call is semantically the same as if
1894:            the current scan had been closed and a openScan() had been called instead.
1895:            The scan is reopened against the same conglomerate, and the scan
1896:            is reopened with the same "scan column list", "hold" and "forUpdate"
1897:            parameters passed in the original openScan.  
1898:            <p>
1899:            The statistics gathered by the scan are not reset to 0 by a reopenScan(),
1900:            rather they continue to accumulate.
1901:            <p>
1902:            Note that this operation is currently only supported on Heap conglomerates.
1903:            Also note that order of rows within are heap are not guaranteed, so for
1904:            instance positioning at a RowLocation in the "middle" of a heap, then
1905:            inserting more data, then continuing the scan is not guaranteed to see
1906:            the new rows - they may be put in the "beginning" of the heap.
1907:
1908:            @param startRowLocation  An existing RowLocation within the conglomerate,
1909:            at which to position the start of the scan.  The scan will begin at this
1910:            location and continue forward until the end of the conglomerate.  
1911:            Positioning at a non-existent RowLocation (ie. an invalid one or one that
1912:            had been deleted), will result in an exception being thrown when the 
1913:            first next operation is attempted.
1914:
1915:            @param qualifier An array of qualifiers which, applied
1916:            to each key, restrict the rows returned by the scan.  Rows
1917:            for which any one of the qualifiers returns false are not
1918:            returned by the scan. If null, all rows are returned.
1919:
1920:            @exception StandardException Standard exception policy.
1921:             **/
1922:            public void reopenScanByRowLocation(RowLocation startRowLocation,
1923:                    Qualifier qualifier[][]) throws StandardException {
1924:                throw StandardException
1925:                        .newException(SQLState.BTREE_UNIMPLEMENTED_FEATURE);
1926:            }
1927:
1928:            /*
1929:             ** Methods of ScanController, which are not supported by btree.
1930:             */
1931:
1932:            /**
1933:            Fetch the location of the current position in the scan.
1934:            @see ScanController#fetchLocation
1935:
1936:            @exception  StandardException  Standard exception policy.
1937:             **/
1938:            public void fetchLocation(RowLocation templateLocation)
1939:                    throws StandardException {
1940:                throw StandardException
1941:                        .newException(SQLState.BTREE_UNIMPLEMENTED_FEATURE);
1942:            }
1943:
1944:            /**
1945:            Return a row location object of the correct type to be
1946:            used in calls to fetchLocation.
1947:            @see GenericScanController#newRowLocationTemplate
1948:
1949:            @exception  StandardException  Standard exception policy.
1950:             **/
1951:            public RowLocation newRowLocationTemplate()
1952:                    throws StandardException {
1953:                throw StandardException
1954:                        .newException(SQLState.BTREE_UNIMPLEMENTED_FEATURE);
1955:            }
1956:
1957:            /**
1958:            Replace the entire row at the current position of the scan.
1959:
1960:            Unimplemented interface by btree, will throw an exception.
1961:
1962:            @see ScanController#replace
1963:            @exception  StandardException  Standard exception policy.
1964:             **/
1965:            public boolean replace(DataValueDescriptor[] row,
1966:                    FormatableBitSet validColumns) throws StandardException {
1967:                throw StandardException
1968:                        .newException(SQLState.BTREE_UNIMPLEMENTED_FEATURE);
1969:            }
1970:
1971:            /*
1972:             ** Methods of ScanManager
1973:             */
1974:
1975:            /**
1976:            Close the scan, a commit or abort is about to happen.
1977:             **/
1978:            public boolean closeForEndTransaction(boolean closeHeldScan)
1979:                    throws StandardException {
1980:                if (!init_hold || closeHeldScan) {
1981:                    // Scan is closed, make sure no access to any state variables
1982:                    positionAtDoneScan(scan_position);
1983:
1984:                    super .close();
1985:
1986:                    // null out so that these object's can get GC'd earlier.
1987:                    this .init_rawtran = null;
1988:                    this .init_template = null;
1989:                    this .init_startKeyValue = null;
1990:                    this .init_qualifier = null;
1991:                    this .init_stopKeyValue = null;
1992:
1993:                    this .getXactMgr().closeMe(this );
1994:
1995:                    return (true);
1996:                } else {
1997:
1998:                    if (this .scan_state == SCAN_INPROGRESS) {
1999:                        if (SanityManager.DEBUG) {
2000:                            SanityManager.ASSERT(scan_position != null);
2001:                        }
2002:
2003:                        if (scan_position.current_positionKey == null) {
2004:                            // save position of scan by key rather than location so 
2005:                            // that we can recover if the page with the position 
2006:                            // disappears while we don't have a scan lock.
2007:
2008:                            savePosition();
2009:                        }
2010:                        this .scan_state = SCAN_HOLD_INPROGRESS;
2011:                    } else if (this .scan_state == SCAN_INIT) {
2012:                        this .scan_state = SCAN_HOLD_INIT;
2013:                    }
2014:
2015:                    super .close();
2016:
2017:                    return (false);
2018:                }
2019:            }
2020:
2021:            /**
2022:             * Do work necessary to maintain the current position in the scan.
2023:             * <p>
2024:             * Save the current position of the scan as a key.
2025:             * Do whatever is necessary to maintain the current position of the scan.
2026:             * For some conglomerates this may be a no-op.
2027:             *
2028:             * <p>
2029:             * @exception  StandardException  Standard exception policy.
2030:             **/
2031:            private void savePosition() throws StandardException {
2032:                if (this .scan_state == SCAN_INPROGRESS) {
2033:                    // Either current_rh or positionKey is valid - the other is null.
2034:                    if (SanityManager.DEBUG) {
2035:                        SanityManager
2036:                                .ASSERT((scan_position.current_rh == null) == (scan_position.current_positionKey != null));
2037:                    }
2038:
2039:                    try {
2040:                        if (scan_position.current_rh != null) {
2041:                            // if scan position is not saved by key, then make it so.
2042:
2043:                            // must reposition to get the page latched.
2044:
2045:                            if (reposition(scan_position, false)) {
2046:                                scan_position.current_positionKey = runtime_mem
2047:                                        .get_row_for_export();
2048:
2049:                                Page page = scan_position.current_leaf
2050:                                        .getPage();
2051:
2052:                                RecordHandle rh = page
2053:                                        .fetchFromSlot(
2054:                                                (RecordHandle) null,
2055:                                                page
2056:                                                        .getSlotNumber(scan_position.current_rh),
2057:                                                scan_position.current_positionKey,
2058:                                                (FetchDescriptor) null, true);
2059:
2060:                                if (SanityManager.DEBUG) {
2061:                                    SanityManager.ASSERT(rh != null);
2062:                                }
2063:
2064:                                scan_position.current_rh = null;
2065:                                scan_position.current_slot = Page.INVALID_SLOT_NUMBER;
2066:
2067:                                // release scan lock now that the row is saved away.
2068:
2069:                                if (scan_position.current_scan_pageno != 0) {
2070:                                    this .getLockingPolicy().unlockScan(
2071:                                            scan_position.current_scan_pageno);
2072:                                    scan_position.current_scan_pageno = 0;
2073:                                }
2074:
2075:                            } else {
2076:                                // this should never happen as we hold the scan lock
2077:                                // on the page while maintaining the position by 
2078:                                // recordhandle - reposition should always work in this
2079:                                // case.
2080:
2081:                                if (SanityManager.DEBUG)
2082:                                    SanityManager
2083:                                            .THROWASSERT("Must always be able to reposition.");
2084:                            }
2085:                        }
2086:
2087:                    } finally {
2088:
2089:                        if (scan_position.current_leaf != null) {
2090:                            // release latch on page
2091:                            scan_position.current_leaf.release();
2092:                            scan_position.current_leaf = null;
2093:                        }
2094:                    }
2095:                }
2096:
2097:            }
2098:
2099:            /**
2100:             * Do work necessary to maintain the current position in the scan.
2101:             * <p>
2102:             * The latched page in the conglomerate "congomid" is changing, do
2103:             * whatever is necessary to maintain the current position of the scan.
2104:             * For some conglomerates this may be a no-op.
2105:             * <p>
2106:             *
2107:             * @param conglom  Conglomerate object of the conglomerate being changed.
2108:             * @param page      Page in the conglomerate being changed.
2109:             *
2110:             * @exception  StandardException  Standard exception policy.
2111:             **/
2112:            public void savePosition(Conglomerate conglom, Page page)
2113:                    throws StandardException {
2114:                // page should be latched by split.  This scan is assuming that latch
2115:                // and reading off it's key from the page under the split's latch.
2116:                // A lock should have already been gotten on this row.
2117:
2118:                if (SanityManager.DEBUG) {
2119:                    SanityManager.ASSERT(page.isLatched());
2120:                }
2121:
2122:                /*
2123:                System.out.println(
2124:                    "Saving position in btree at top: " +
2125:                    " this.conglomerate = " +  this.conglomerate        +
2126:                    " this.scan_state   = " +  this.scan_state);
2127:                SanityManager.DEBUG_PRINT("savePosition()", 
2128:                    "Saving position in btree at top: " +
2129:                    " this.conglomerate = " +  this.conglomerate        +
2130:                    " this.scan_state   = " +  this.scan_state);
2131:                 */
2132:
2133:                if ((this .getConglomerate() == conglom)
2134:                        && (this .scan_state == SCAN_INPROGRESS)) {
2135:                    // Either current_rh or positionKey is valid - the other is null.
2136:                    if (SanityManager.DEBUG) {
2137:                        SanityManager
2138:                                .ASSERT((scan_position.current_rh == null) == (scan_position.current_positionKey != null));
2139:                    }
2140:
2141:                    /*
2142:                    SanityManager.DEBUG_PRINT("savePosition()", 
2143:                        "Saving position in btree: " +
2144:                        ";current_scan_pageno = " + this.current_scan_pageno +
2145:                        "this.current_rh = " + this.current_rh +
2146:                        ";page.getPageNumber() = " + page.getPageNumber() +
2147:                        ((this.current_rh != null) ?
2148:                            (";this.current_rh.getPageNumber() = " +
2149:                             this.current_rh.getPageNumber()) : ""));
2150:                     */
2151:
2152:                    if (scan_position.current_rh != null
2153:                            && page.getPageNumber() == scan_position.current_rh
2154:                                    .getPageNumber()) {
2155:                        scan_position.current_positionKey = runtime_mem
2156:                                .get_row_for_export();
2157:
2158:                        RecordHandle rh = page.fetchFromSlot(
2159:                                (RecordHandle) null,
2160:                                page.getSlotNumber(scan_position.current_rh),
2161:                                scan_position.current_positionKey,
2162:                                (FetchDescriptor) null, true);
2163:
2164:                        if (SanityManager.DEBUG) {
2165:                            SanityManager.ASSERT(rh != null);
2166:                        }
2167:
2168:                        scan_position.current_rh = null;
2169:                        scan_position.current_slot = Page.INVALID_SLOT_NUMBER;
2170:
2171:                        // release the scan lock now that we have saved away the row.
2172:
2173:                        if (scan_position.current_scan_pageno != 0) {
2174:                            this .getLockingPolicy().unlockScan(
2175:                                    scan_position.current_scan_pageno);
2176:                            scan_position.current_scan_pageno = 0;
2177:                        }
2178:                    }
2179:                }
2180:            }
2181:
2182:            public RecordHandle getCurrentRecordHandleForDebugging() {
2183:                return (scan_position.current_rh);
2184:            }
2185:
2186:            /*
2187:             ** Standard toString() method.  Prints out current position in scan.
2188:             */
2189:            public String toString() {
2190:                if (SanityManager.DEBUG) {
2191:                    String string = "\n\tbtree = "
2192:                            + this .getConglomerate()
2193:                            + "\n\tscan direction       = "
2194:                            + (this  instanceof  BTreeForwardScan ? "forward"
2195:                                    : (this  instanceof  BTreeMaxScan ? "backward"
2196:                                            : "illegal"))
2197:                            + "\n\t(scan_state:"
2198:                            + (this .scan_state == SCAN_INIT ? "SCAN_INIT"
2199:                                    : this .scan_state == SCAN_INPROGRESS ? "SCAN_INPROGRESS"
2200:                                            : this .scan_state == SCAN_DONE ? "SCAN_DONE"
2201:                                                    : this .scan_state == SCAN_HOLD_INIT ? "SCAN_HOLD_INIT"
2202:                                                            : this .scan_state == SCAN_HOLD_INPROGRESS ? "SCAN_HOLD_INPROGRESS"
2203:                                                                    : "BAD_SCAN_STATE")
2204:                            + "\n\trh:"
2205:                            + scan_position.current_rh
2206:                            + "\n\tkey:"
2207:                            + scan_position.current_positionKey
2208:                            + ")"
2209:                            + "\n\tinit_rawtran = "
2210:                            + init_rawtran
2211:                            + "\n\tinit_hold = "
2212:                            + init_hold
2213:                            + "\n\tinit_forUpdate = "
2214:                            + init_forUpdate
2215:                            + "\n\tinit_useUpdateLocks = "
2216:                            + init_useUpdateLocks
2217:                            + "\n\tinit_scanColumnList = "
2218:                            + init_scanColumnList
2219:                            + "\n\tinit_scanColumnList.size() = "
2220:                            + ((init_scanColumnList != null ? init_scanColumnList
2221:                                    .size()
2222:                                    : 0))
2223:                            + "\n\tinit_template = "
2224:                            + RowUtil.toString(init_template)
2225:                            + "\n\tinit_startKeyValue = "
2226:                            + RowUtil.toString(init_startKeyValue)
2227:                            + "\n\tinit_startSearchOperator = "
2228:                            + (init_startSearchOperator == ScanController.GE ? "GE"
2229:                                    : (init_startSearchOperator == ScanController.GT ? "GT"
2230:                                            : Integer
2231:                                                    .toString(init_startSearchOperator)))
2232:                            + "\n\tinit_qualifier[]         = "
2233:                            + init_qualifier
2234:                            + "\n\tinit_stopKeyValue = "
2235:                            + RowUtil.toString(init_stopKeyValue)
2236:                            + "\n\tinit_stopSearchOperator = "
2237:                            + (init_stopSearchOperator == ScanController.GE ? "GE"
2238:                                    : (init_stopSearchOperator == ScanController.GT ? "GT"
2239:                                            : Integer
2240:                                                    .toString(init_stopSearchOperator)))
2241:                            + "\n\tstat_numpages_visited         = "
2242:                            + stat_numpages_visited
2243:                            + "\n\tstat_numrows_visited          = "
2244:                            + stat_numrows_visited
2245:                            + "\n\tstat_numrows_qualified        = "
2246:                            + stat_numrows_qualified
2247:                            + "\n\tstat_numdeleted_rows_visited  = "
2248:                            + stat_numdeleted_rows_visited;
2249:
2250:                    return (string);
2251:                } else {
2252:                    return (null);
2253:                }
2254:            }
2255:        }
w__w_w___.___j__a__va__2s.co__m__ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.