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

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


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.sql.execute.ScrollInsensitiveResultSet
0004:
0005:           Licensed to the Apache Software Foundation (ASF) under one or more
0006:           contributor license agreements.  See the NOTICE file distributed with
0007:           this work for additional information regarding copyright ownership.
0008:           The ASF licenses this file to you under the Apache License, Version 2.0
0009:           (the "License"); you may not use this file except in compliance with
0010:           the License.  You may obtain a copy of the License at
0011:
0012:              http://www.apache.org/licenses/LICENSE-2.0
0013:
0014:           Unless required by applicable law or agreed to in writing, software
0015:           distributed under the License is distributed on an "AS IS" BASIS,
0016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:           See the License for the specific language governing permissions and
0018:           limitations under the License.
0019:
0020:         */
0021:
0022:        package org.apache.derby.impl.sql.execute;
0023:
0024:        import org.apache.derby.iapi.services.loader.GeneratedMethod;
0025:
0026:        import org.apache.derby.iapi.services.monitor.Monitor;
0027:
0028:        import org.apache.derby.iapi.services.sanity.SanityManager;
0029:
0030:        import org.apache.derby.iapi.sql.execute.CursorResultSet;
0031:        import org.apache.derby.iapi.sql.execute.ExecRow;
0032:        import org.apache.derby.iapi.sql.execute.ExecutionContext;
0033:        import org.apache.derby.iapi.sql.execute.NoPutResultSet;
0034:
0035:        import org.apache.derby.iapi.sql.Activation;
0036:        import org.apache.derby.iapi.sql.Row;
0037:
0038:        import org.apache.derby.iapi.store.access.ConglomerateController;
0039:        import org.apache.derby.iapi.store.access.ScanController;
0040:        import org.apache.derby.iapi.store.access.TransactionController;
0041:
0042:        import org.apache.derby.iapi.types.RowLocation;
0043:        import org.apache.derby.iapi.types.DataValueDescriptor;
0044:
0045:        import org.apache.derby.iapi.error.StandardException;
0046:        import org.apache.derby.iapi.reference.SQLState;
0047:
0048:        import org.apache.derby.iapi.store.access.BackingStoreHashtable;
0049:        import org.apache.derby.iapi.services.io.FormatableBitSet;
0050:
0051:        import org.apache.derby.iapi.types.SQLBoolean;
0052:        import org.apache.derby.iapi.types.SQLInteger;
0053:
0054:        /**
0055:         *
0056:         * Provide insensitive scrolling functionality for the underlying
0057:         * result set.  We build a disk backed hash table of rows as the 
0058:         * user scrolls forward, with the position as the key.
0059:         *
0060:         * For read-only result sets the hash table will containg the
0061:         * following columns:
0062:         *<pre>
0063:         *  +-------------------------------+
0064:         *  | KEY                           |
0065:         *  +-------------------------------+
0066:         *  | Row                           |
0067:         *  +-------------------------------+
0068:         *</pre>
0069:         * where key is the position of the row in the result set and row is the data.
0070:         *
0071:         * And for updatable result sets it will contain:
0072:         * <pre>
0073:         *  +-------------------------------+
0074:         *  | KEY                           | [0]
0075:         *  +-------------------------------+
0076:         *  | RowLocation                   | [POS_ROWLOCATION]
0077:         *  +-------------------------------+
0078:         *  | Deleted                       | [POS_ROWDELETED]
0079:         *  +-------------------------------+
0080:         *  | Updated                       | [POS_ROWUPDATED]
0081:         *  +-------------------------------+
0082:         *  | Row                           | [extraColumns ... n]
0083:         *  +-------------------------------+
0084:         *</pre>
0085:         * where key is the position of the row in the result set, rowLocation is
0086:         * the row location of that row in the Heap, Deleted indicates whether the
0087:         * row has been deleted, Updated indicates whether the row has been updated,
0088:         * and row is the data.
0089:         *
0090:         */
0091:
0092:        public class ScrollInsensitiveResultSet extends NoPutResultSetImpl
0093:                implements  CursorResultSet {
0094:            /*
0095:             ** Set in constructor and not altered during life of object.
0096:             */
0097:
0098:            public NoPutResultSet source;
0099:
0100:            private int sourceRowWidth;
0101:
0102:            private BackingStoreHashtable ht;
0103:            private ExecRow resultRow;
0104:
0105:            // Scroll tracking
0106:            private int positionInSource;
0107:            private int currentPosition;
0108:            private int lastPosition;
0109:            private boolean seenFirst;
0110:            private boolean seenLast;
0111:            private boolean beforeFirst = true;
0112:            private boolean afterLast;
0113:
0114:            public int numFromHashTable;
0115:            public int numToHashTable;
0116:
0117:            private int maxRows;
0118:
0119:            private boolean keepAfterCommit;
0120:
0121:            /* The hash table will contain a different number of extra columns depending
0122:             * on whether the result set is updatable or not.
0123:             * extraColumns will contain the number of extra columns on the hash table,
0124:             * 1 for read-only result sets and LAST_EXTRA_COLUMN + 1 for updatable 
0125:             * result sets.
0126:             */
0127:            private int extraColumns;
0128:
0129:            /* positionInHashTable is used for getting a row from the hash table. Prior
0130:             * to getting the row, positionInHashTable will be set to the desired KEY.
0131:             */
0132:            private SQLInteger positionInHashTable;
0133:
0134:            /* Reference to the target result set. Target is used for updatable result
0135:             * sets in order to keep the target result set on the same row as the
0136:             * ScrollInsensitiveResultSet.  
0137:             */
0138:            private CursorResultSet target;
0139:
0140:            /* If the last row was fetched from the HashTable, updatable result sets
0141:             * need to be positioned in the last fetched row before resuming the 
0142:             * fetch from core.
0143:             */
0144:            private boolean needsRepositioning;
0145:
0146:            /* Position of the different fields in the hash table row for updatable
0147:             * result sets 
0148:             */
0149:            private static final int POS_ROWLOCATION = 1;
0150:            private static final int POS_ROWDELETED = 2;
0151:            private static final int POS_ROWUPDATED = 3;
0152:            private static final int LAST_EXTRA_COLUMN = 3;
0153:
0154:            /**
0155:             * Constructor for a ScrollInsensitiveResultSet
0156:             *
0157:             * @param source					The NoPutResultSet from which to get rows
0158:             *									to scroll through
0159:             * @param activation				The activation for this execution
0160:             * @param resultSetNumber			The resultSetNumber
0161:             * @param sourceRowWidth			# of columns in the source row
0162:             *
0163:             * @exception StandardException	on error
0164:             */
0165:
0166:            public ScrollInsensitiveResultSet(NoPutResultSet source,
0167:                    Activation activation, int resultSetNumber,
0168:                    int sourceRowWidth, double optimizerEstimatedRowCount,
0169:                    double optimizerEstimatedCost) throws StandardException {
0170:                super (activation, resultSetNumber, optimizerEstimatedRowCount,
0171:                        optimizerEstimatedCost);
0172:                this .source = source;
0173:                this .sourceRowWidth = sourceRowWidth;
0174:                keepAfterCommit = activation.getResultSetHoldability();
0175:                maxRows = activation.getMaxRows();
0176:                if (SanityManager.DEBUG) {
0177:                    SanityManager.ASSERT(maxRows != -1,
0178:                            "maxRows not expected to be -1");
0179:                }
0180:
0181:                constructorTime += getElapsedMillis(beginTime);
0182:
0183:                positionInHashTable = new SQLInteger();
0184:                needsRepositioning = false;
0185:                if (isForUpdate()) {
0186:                    target = ((CursorActivation) activation)
0187:                            .getTargetResultSet();
0188:                    extraColumns = LAST_EXTRA_COLUMN + 1;
0189:                } else {
0190:                    target = null;
0191:                    extraColumns = 1;
0192:                }
0193:            }
0194:
0195:            //
0196:            // ResultSet interface (leftover from NoPutResultSet)
0197:            //
0198:
0199:            /**
0200:             * open a scan on the source. scan parameters are evaluated
0201:             * at each open, so there is probably some way of altering
0202:             * their values...
0203:             *
0204:             * @exception StandardException thrown on failure 
0205:             */
0206:            public void openCore() throws StandardException {
0207:                beginTime = getCurrentTimeMillis();
0208:                if (SanityManager.DEBUG)
0209:                    SanityManager.ASSERT(!isOpen,
0210:                            "ScrollInsensitiveResultSet already open");
0211:
0212:                source.openCore();
0213:                isOpen = true;
0214:                numOpens++;
0215:
0216:                /* Create the hash table.  We pass
0217:                 * null in as the row source as we will
0218:                 * build the hash table on demand as
0219:                 * the user scrolls.
0220:                 * The 1st column, the position in the
0221:                 * scan, will be the key column.
0222:                 */
0223:                final int[] keyCols = new int[] { 0 };
0224:
0225:                /* We don't use the optimizer row count for this because it could be
0226:                 * wildly pessimistic.  We only use Hash tables when the optimizer row count
0227:                 * is within certain bounds.  We have no alternative for scrolling insensitive 
0228:                 * cursors so we'll just trust that it will fit.
0229:                 * We need BackingStoreHashtable to actually go to disk when it doesn't fit.
0230:                 * This is a known limitation.
0231:                 */
0232:                ht = new BackingStoreHashtable(getTransactionController(),
0233:                        null,
0234:                        keyCols,
0235:                        false,
0236:                        -1, // don't trust optimizer row count
0237:                        HashScanResultSet.DEFAULT_MAX_CAPACITY,
0238:                        HashScanResultSet.DEFAULT_INITIAL_CAPACITY,
0239:                        HashScanResultSet.DEFAULT_MAX_CAPACITY, false,
0240:                        keepAfterCommit);
0241:
0242:                openTime += getElapsedMillis(beginTime);
0243:                setBeforeFirstRow();
0244:            }
0245:
0246:            /**
0247:             * reopen a scan on the table. scan parameters are evaluated
0248:             * at each open, so there is probably some way of altering
0249:             * their values...
0250:             *
0251:             * @exception StandardException thrown if cursor finished.
0252:             */
0253:            public void reopenCore() throws StandardException {
0254:                boolean constantEval = true;
0255:
0256:                beginTime = getCurrentTimeMillis();
0257:
0258:                if (SanityManager.DEBUG) {
0259:                    SanityManager.ASSERT(isOpen,
0260:                            "ScrollInsensitiveResultSet already open");
0261:                    SanityManager
0262:                            .THROWASSERT("reopenCore() not expected to be called");
0263:                }
0264:                setBeforeFirstRow();
0265:            }
0266:
0267:            /**
0268:             * Returns the row at the absolute position from the query, 
0269:             * and returns NULL when there is no such position.
0270:             * (Negative position means from the end of the result set.)
0271:             * Moving the cursor to an invalid position leaves the cursor
0272:             * positioned either before the first row (negative position)
0273:             * or after the last row (positive position).
0274:             * NOTE: An exception will be thrown on 0.
0275:             *
0276:             * @param row	The position.
0277:             * @return	The row at the absolute position, or NULL if no such position.
0278:             *
0279:             * @exception StandardException		Thrown on failure
0280:             * @see Row
0281:             */
0282:            public ExecRow getAbsoluteRow(int row) throws StandardException {
0283:                if (!isOpen) {
0284:                    throw StandardException.newException(
0285:                            SQLState.LANG_RESULT_SET_NOT_OPEN, "absolute");
0286:                }
0287:
0288:                attachStatementContext();
0289:
0290:                if (SanityManager.DEBUG) {
0291:                    if (!isTopResultSet) {
0292:                        SanityManager.THROWASSERT(this 
0293:                                + "expected to be the top ResultSet");
0294:                    }
0295:                }
0296:
0297:                // Absolute 0 is defined to be before first!
0298:                if (row == 0) {
0299:                    setBeforeFirstRow();
0300:                    return null;
0301:                }
0302:
0303:                if (seenLast && row > lastPosition) {
0304:                    return setAfterLastRow();
0305:                }
0306:
0307:                if (row > 0) {
0308:                    // position is from the start of the result set
0309:                    if (row <= positionInSource) {
0310:                        // We've already seen the row before
0311:                        return getRowFromHashTable(row);
0312:                    }
0313:
0314:                    /* We haven't seen the row yet, scan until we find
0315:                     * it or we get to the end.
0316:                     */
0317:                    int diff = row - positionInSource;
0318:                    ExecRow result = null;
0319:                    while (diff > 0) {
0320:                        if ((result = getNextRowFromSource()) != null) {
0321:                            diff--;
0322:                        } else {
0323:                            break;
0324:                        }
0325:                    }
0326:                    if (result != null) {
0327:                        result = getRowFromHashTable(row);
0328:                    }
0329:                    currentRow = result;
0330:                    return result;
0331:                } else if (row < 0) {
0332:                    // position is from the end of the result set
0333:
0334:                    // Get the last row, if we haven't already
0335:                    if (!seenLast) {
0336:                        getLastRow();
0337:                    }
0338:
0339:                    // Note, for negative values position is from beyond the end
0340:                    // of the result set, e.g. absolute(-1) points to the last row
0341:                    int beyondResult = lastPosition + 1;
0342:                    if (beyondResult + row > 0) {
0343:                        // valid row
0344:                        return getRowFromHashTable(beyondResult + row);
0345:                    } else {
0346:                        // position before the beginning of the result set
0347:                        return setBeforeFirstRow();
0348:                    }
0349:                }
0350:
0351:                currentRow = null;
0352:                return null;
0353:            }
0354:
0355:            /**
0356:             * Returns the row at the relative position from the current
0357:             * cursor position, and returns NULL when there is no such position.
0358:             * (Negative position means toward the beginning of the result set.)
0359:             * Moving the cursor to an invalid position leaves the cursor
0360:             * positioned either before the first row (negative position)
0361:             * or after the last row (positive position).
0362:             * NOTE: 0 is valid.
0363:             * NOTE: An exception is thrown if the cursor is not currently
0364:             * positioned on a row.
0365:             *
0366:             * @param row	The position.
0367:             * @return	The row at the relative position, or NULL if no such position.
0368:             *
0369:             * @exception StandardException		Thrown on failure
0370:             * @see Row
0371:             */
0372:            public ExecRow getRelativeRow(int row) throws StandardException {
0373:                if (!isOpen) {
0374:                    throw StandardException.newException(
0375:                            SQLState.LANG_RESULT_SET_NOT_OPEN, "relative");
0376:                }
0377:
0378:                attachStatementContext();
0379:
0380:                if (SanityManager.DEBUG) {
0381:                    if (!isTopResultSet) {
0382:                        SanityManager.THROWASSERT(this 
0383:                                + "expected to be the top ResultSet");
0384:                    }
0385:                }
0386:
0387:                // Return the current row for 0
0388:                if (row == 0) {
0389:                    if (beforeFirst || afterLast || currentPosition == 0) {
0390:                        return null;
0391:                    } else {
0392:                        return getRowFromHashTable(currentPosition);
0393:                    }
0394:                } else if (row > 0) {
0395:                    return getAbsoluteRow(currentPosition + row);
0396:                } else {
0397:                    // row < 0
0398:                    if (currentPosition + row < 0) {
0399:                        return setBeforeFirstRow();
0400:                    }
0401:                    return getAbsoluteRow(currentPosition + row);
0402:                }
0403:            }
0404:
0405:            /**
0406:             * Sets the current position to before the first row and returns NULL
0407:             * because there is no current row.
0408:             *
0409:             * @return	NULL.
0410:             *
0411:             * @see Row
0412:             */
0413:            public ExecRow setBeforeFirstRow() {
0414:                currentPosition = 0;
0415:                beforeFirst = true;
0416:                afterLast = false;
0417:                currentRow = null;
0418:                return null;
0419:            }
0420:
0421:            /**
0422:             * Returns the first row from the query, and returns NULL when there
0423:             * are no rows.
0424:             *
0425:             * @return	The first row, or NULL if no rows.
0426:             *
0427:             * @exception StandardException		Thrown on failure
0428:             * @see Row
0429:             */
0430:            public ExecRow getFirstRow() throws StandardException {
0431:                if (!isOpen) {
0432:                    throw StandardException.newException(
0433:                            SQLState.LANG_RESULT_SET_NOT_OPEN, "first");
0434:                }
0435:
0436:                /* Get the row from the hash table if
0437:                 * we have already seen it before.
0438:                 */
0439:                if (seenFirst) {
0440:                    return getRowFromHashTable(1);
0441:                }
0442:
0443:                attachStatementContext();
0444:
0445:                if (SanityManager.DEBUG) {
0446:                    if (!isTopResultSet) {
0447:                        SanityManager.THROWASSERT(this 
0448:                                + "expected to be the top ResultSet");
0449:                    }
0450:                }
0451:
0452:                return getNextRowCore();
0453:            }
0454:
0455:            /**
0456:             *
0457:             * @exception StandardException thrown on failure 
0458:             */
0459:            public ExecRow getNextRowCore() throws StandardException {
0460:                ExecRow result = null;
0461:
0462:                beginTime = getCurrentTimeMillis();
0463:                if (!isOpen)
0464:                    throw StandardException.newException(
0465:                            SQLState.LANG_RESULT_SET_NOT_OPEN, "next");
0466:
0467:                if (seenLast && currentPosition == lastPosition) {
0468:                    return setAfterLastRow();
0469:                }
0470:
0471:                /* Should we get the next row from the source or the hash table? */
0472:                if (currentPosition == positionInSource) {
0473:                    /* Current position is same as position in source.
0474:                     * Get row from the source.
0475:                     */
0476:                    result = getNextRowFromSource();
0477:                    if (result != null) {
0478:                        result = getRowFromHashTable(currentPosition);
0479:                    }
0480:                } else if (currentPosition < positionInSource) {
0481:                    /* Current position is before position in source.
0482:                     * Get row from the hash table.
0483:                     */
0484:                    result = getRowFromHashTable(currentPosition + 1);
0485:                } else {
0486:                    result = null;
0487:                }
0488:
0489:                if (result != null) {
0490:                    rowsSeen++;
0491:                    afterLast = false;
0492:                }
0493:
0494:                currentRow = result;
0495:                setCurrentRow(currentRow);
0496:                beforeFirst = false;
0497:
0498:                nextTime += getElapsedMillis(beginTime);
0499:
0500:                return result;
0501:            }
0502:
0503:            /**
0504:             * Returns the previous row from the query, and returns NULL when there
0505:             * are no more previous rows.
0506:             *
0507:             * @return	The previous row, or NULL if no more previous rows.
0508:             *
0509:             * @exception StandardException		Thrown on failure
0510:             * @see Row
0511:             */
0512:            public ExecRow getPreviousRow() throws StandardException {
0513:                if (!isOpen) {
0514:                    throw StandardException.newException(
0515:                            SQLState.LANG_RESULT_SET_NOT_OPEN, "next");
0516:                }
0517:
0518:                if (SanityManager.DEBUG) {
0519:                    if (!isTopResultSet) {
0520:                        SanityManager.THROWASSERT(this 
0521:                                + "expected to be the top ResultSet");
0522:                    }
0523:                }
0524:
0525:                /* No row if we are positioned before the first row
0526:                 * or the result set is empty.
0527:                 */
0528:                if (beforeFirst || currentPosition == 0) {
0529:                    currentRow = null;
0530:                    return null;
0531:                }
0532:
0533:                // Get the last row, if we are after it
0534:                if (afterLast) {
0535:                    // Special case for empty tables
0536:                    if (lastPosition == 0) {
0537:                        afterLast = false;
0538:                        beforeFirst = false;
0539:                        currentRow = null;
0540:                        return null;
0541:                    } else {
0542:                        return getRowFromHashTable(lastPosition);
0543:                    }
0544:                }
0545:
0546:                // Move back 1
0547:                currentPosition--;
0548:                if (currentPosition == 0) {
0549:                    setBeforeFirstRow();
0550:                    return null;
0551:                }
0552:                return getRowFromHashTable(currentPosition);
0553:            }
0554:
0555:            /**
0556:             * Returns the last row from the query, and returns NULL when there
0557:             * are no rows.
0558:             *
0559:             * @return	The last row, or NULL if no rows.
0560:             *
0561:             * @exception StandardException		Thrown on failure
0562:             * @see Row
0563:             */
0564:            public ExecRow getLastRow() throws StandardException {
0565:                if (!isOpen) {
0566:                    throw StandardException.newException(
0567:                            SQLState.LANG_RESULT_SET_NOT_OPEN, "next");
0568:                }
0569:
0570:                if (!seenLast) {
0571:                    attachStatementContext();
0572:
0573:                    if (SanityManager.DEBUG) {
0574:                        if (!isTopResultSet) {
0575:                            SanityManager.THROWASSERT(this 
0576:                                    + "expected to be the top ResultSet");
0577:                        }
0578:                    }
0579:
0580:                    /* Scroll to the end, filling the hash table as
0581:                     * we scroll, and return the last row that we find.
0582:                     */
0583:                    ExecRow result = null;
0584:                    while ((result = getNextRowFromSource()) != null)
0585:                        ;
0586:                }
0587:
0588:                if (SanityManager.DEBUG && !seenLast) {
0589:                    SanityManager.THROWASSERT(this 
0590:                            + "expected to have seen last");
0591:                }
0592:
0593:                beforeFirst = false;
0594:                afterLast = false;
0595:
0596:                // Special case if table is empty
0597:                if (lastPosition == 0) {
0598:                    currentRow = null;
0599:                    return null;
0600:                } else {
0601:                    return getRowFromHashTable(lastPosition);
0602:                }
0603:            }
0604:
0605:            /**
0606:             * Sets the current position to after the last row and returns NULL
0607:             * because there is no current row.
0608:             *
0609:             * @return	NULL.
0610:             *
0611:             * @exception StandardException		Thrown on failure
0612:             * @see Row
0613:             */
0614:            public ExecRow setAfterLastRow() throws StandardException {
0615:                if (!seenLast) {
0616:                    getLastRow();
0617:                }
0618:                if (lastPosition == 0) {
0619:                    // empty rs special case
0620:                    currentPosition = 0;
0621:                    afterLast = false;
0622:                } else {
0623:                    currentPosition = lastPosition + 1;
0624:                    afterLast = true;
0625:                }
0626:
0627:                beforeFirst = false;
0628:                currentRow = null;
0629:                return null;
0630:            }
0631:
0632:            /**
0633:             * Determine if the cursor is before the first row in the result 
0634:             * set.   
0635:             *
0636:             * @return true if before the first row, false otherwise. Returns
0637:             * false when the result set contains no rows.
0638:             * @exception StandardException Thrown on error.
0639:             */
0640:            public boolean checkRowPosition(int isType)
0641:                    throws StandardException {
0642:                switch (isType) {
0643:                case ISBEFOREFIRST:
0644:
0645:                    if (!beforeFirst) {
0646:                        return false;
0647:                    }
0648:
0649:                    //  Spec says to return false if result set is empty
0650:                    if (seenFirst) {
0651:                        return true;
0652:                    } else {
0653:                        ExecRow firstRow = getFirstRow();
0654:                        if (firstRow == null) {
0655:                            // ResultSet is empty
0656:                            return false;
0657:                        } else {
0658:                            // ResultSet is not empty - reset position
0659:                            getPreviousRow();
0660:                            return true;
0661:                        }
0662:                    }
0663:                case ISFIRST:
0664:                    return (currentPosition == 1);
0665:                case ISLAST:
0666:                    if (beforeFirst || afterLast || currentPosition == 0
0667:                            || currentPosition < positionInSource) {
0668:                        return false;
0669:                    }
0670:
0671:                    /* If we have seen the last row, we can tell if we are 
0672:                     * on it by comparing currentPosition with lastPosition.
0673:                     * Otherwise, we check if there is a next row.
0674:                     */
0675:                    if (seenLast) {
0676:                        return (currentPosition == lastPosition);
0677:                    } else {
0678:                        final int savePosition = currentPosition;
0679:                        final boolean retval = (getNextRowFromSource() == null);
0680:                        getRowFromHashTable(savePosition);
0681:                        return retval;
0682:                    }
0683:                case ISAFTERLAST:
0684:                    return afterLast;
0685:                default:
0686:                    return false;
0687:                }
0688:            }
0689:
0690:            /**
0691:             * Returns the row number of the current row.  Row
0692:             * numbers start from 1 and go to 'n'.  Corresponds
0693:             * to row numbering used to position current row
0694:             * in the result set (as per JDBC).
0695:             *
0696:             * @return	the row number, or 0 if not on a row
0697:             *
0698:             */
0699:            public int getRowNumber() {
0700:                return currentRow == null ? 0 : currentPosition;
0701:            }
0702:
0703:            /* Get the next row from the source ResultSet tree and insert into the hash table */
0704:            private ExecRow getNextRowFromSource() throws StandardException {
0705:                ExecRow sourceRow = null;
0706:                ExecRow result = null;
0707:
0708:                /* Don't give back more rows than requested */
0709:                if (maxRows > 0 && maxRows == positionInSource) {
0710:                    seenLast = true;
0711:                    lastPosition = positionInSource;
0712:                    afterLast = true;
0713:                    return null;
0714:                }
0715:
0716:                if (needsRepositioning) {
0717:                    positionInLastFetchedRow();
0718:                    needsRepositioning = false;
0719:                }
0720:                sourceRow = source.getNextRowCore();
0721:
0722:                if (sourceRow != null) {
0723:                    seenFirst = true;
0724:                    beforeFirst = false;
0725:
0726:                    long beginTCTime = getCurrentTimeMillis();
0727:                    /* If this is the first row from the source then we create a new row
0728:                     * for use when fetching from the hash table.
0729:                     */
0730:                    if (resultRow == null) {
0731:                        resultRow = activation.getExecutionFactory()
0732:                                .getValueRow(sourceRowWidth);
0733:                    }
0734:
0735:                    positionInSource++;
0736:                    currentPosition = positionInSource;
0737:
0738:                    RowLocation rowLoc = null;
0739:                    if (source.isForUpdate()) {
0740:                        rowLoc = ((CursorResultSet) source).getRowLocation();
0741:                    }
0742:
0743:                    addRowToHashTable(sourceRow, currentPosition, rowLoc, false);
0744:
0745:                }
0746:                // Remember whether or not we're past the end of the table
0747:                else {
0748:                    if (!seenLast) {
0749:                        lastPosition = positionInSource;
0750:                    }
0751:                    seenLast = true;
0752:                    // Special case for empty table (afterLast is never true)
0753:                    if (positionInSource == 0) {
0754:                        afterLast = false;
0755:                    } else {
0756:                        afterLast = true;
0757:                        currentPosition = positionInSource + 1;
0758:                    }
0759:                }
0760:
0761:                return sourceRow;
0762:            }
0763:
0764:            /**
0765:             * If the result set has been opened,
0766:             * close the open scan.
0767:             *
0768:             * @exception StandardException thrown on error
0769:             */
0770:            public void close() throws StandardException {
0771:                beginTime = getCurrentTimeMillis();
0772:                if (isOpen) {
0773:                    currentRow = null;
0774:                    source.close();
0775:
0776:                    if (ht != null) {
0777:                        ht.close();
0778:                        ht = null;
0779:                    }
0780:
0781:                    super .close();
0782:                } else if (SanityManager.DEBUG)
0783:                    SanityManager.DEBUG("CloseRepeatInfo",
0784:                            "Close of ScrollInsensitiveResultSet repeated");
0785:                setBeforeFirstRow();
0786:
0787:                closeTime += getElapsedMillis(beginTime);
0788:            }
0789:
0790:            public void finish() throws StandardException {
0791:                source.finish();
0792:                finishAndRTS();
0793:            }
0794:
0795:            /**
0796:             * Return the total amount of time spent in this ResultSet
0797:             *
0798:             * @param type	CURRENT_RESULTSET_ONLY - time spent only in this ResultSet
0799:             *				ENTIRE_RESULTSET_TREE  - time spent in this ResultSet and below.
0800:             *
0801:             * @return long		The total amount of time spent (in milliseconds).
0802:             */
0803:            public long getTimeSpent(int type) {
0804:                long totTime = constructorTime + openTime + nextTime
0805:                        + closeTime;
0806:
0807:                if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY) {
0808:                    return totTime - source.getTimeSpent(ENTIRE_RESULTSET_TREE);
0809:                } else {
0810:                    return totTime;
0811:                }
0812:            }
0813:
0814:            //
0815:            // CursorResultSet interface
0816:            //
0817:
0818:            /**
0819:             * Gets information from its source. We might want
0820:             * to have this take a CursorResultSet in its constructor some day,
0821:             * instead of doing a cast here?
0822:             *
0823:             * @see CursorResultSet
0824:             *
0825:             * @return the row location of the current cursor row.
0826:             *
0827:             * @exception StandardException thrown on failure 
0828:             */
0829:            public RowLocation getRowLocation() throws StandardException {
0830:                if (SanityManager.DEBUG)
0831:                    SanityManager.ASSERT(source instanceof  CursorResultSet,
0832:                            "source not CursorResultSet");
0833:                return ((CursorResultSet) source).getRowLocation();
0834:            }
0835:
0836:            /**
0837:             * Gets information from last getNextRow call.
0838:             *
0839:             * @see CursorResultSet
0840:             *
0841:             * @return the last row returned.
0842:             */
0843:            /* RESOLVE - this should return activation.getCurrentRow(resultSetNumber),
0844:             * once there is such a method.  (currentRow is redundant)
0845:             */
0846:            public ExecRow getCurrentRow() throws StandardException {
0847:                if (isForUpdate() && isDeleted()) {
0848:                    return null;
0849:                } else {
0850:                    return currentRow;
0851:                }
0852:            }
0853:
0854:            //
0855:            // class implementation
0856:            //
0857:
0858:            /**
0859:             * Add a row to the backing hash table, keyed on position.
0860:             * When a row gets updated when using scrollable insensitive updatable
0861:             * result sets, the old entry for the row will be deleted from the hash 
0862:             * table and this method will be called to add the new values for the row
0863:             * to the hash table, with the parameter rowUpdated = true so as to mark 
0864:             * the row as updated. The latter is done in order to implement 
0865:             * detectability of own changes for result sets of this type.
0866:             *
0867:             * @param sourceRow	The row to add.
0868:             * @param position The key
0869:             * @param rowLoc The rowLocation of the row to add.
0870:             * @param rowUpdated Indicates whether the row has been updated.
0871:             *
0872:             */
0873:            private void addRowToHashTable(ExecRow sourceRow, int position,
0874:                    RowLocation rowLoc, boolean rowUpdated)
0875:                    throws StandardException {
0876:                DataValueDescriptor[] hashRowArray = new DataValueDescriptor[sourceRowWidth
0877:                        + extraColumns];
0878:                // 1st element is the key
0879:                hashRowArray[0] = new SQLInteger(position);
0880:                if (isForUpdate()) {
0881:                    hashRowArray[POS_ROWLOCATION] = rowLoc.getClone();
0882:                    hashRowArray[POS_ROWDELETED] = new SQLBoolean(false);
0883:                    hashRowArray[POS_ROWUPDATED] = new SQLBoolean(rowUpdated);
0884:                }
0885:
0886:                /* Copy rest of elements from sourceRow.
0887:                 * NOTE: We need to clone the source row
0888:                 * and we do our own cloning since the 1st column
0889:                 * is not a wrapper.
0890:                 */
0891:                DataValueDescriptor[] sourceRowArray = sourceRow.getRowArray();
0892:
0893:                System.arraycopy(sourceRowArray, 0, hashRowArray, extraColumns,
0894:                        sourceRowArray.length);
0895:
0896:                ht.put(true, hashRowArray);
0897:
0898:                numToHashTable++;
0899:            }
0900:
0901:            /**
0902:             * Get the row at the specified position
0903:             * from the hash table.
0904:             *
0905:             * @param position	The specified position.
0906:             *
0907:             * @return	The row at that position.
0908:             *
0909:             * @exception StandardException thrown on failure 
0910:             */
0911:            private ExecRow getRowFromHashTable(int position)
0912:                    throws StandardException {
0913:
0914:                // Get the row from the hash table
0915:                positionInHashTable.setValue(position);
0916:                DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) ht
0917:                        .get(positionInHashTable);
0918:
0919:                if (SanityManager.DEBUG) {
0920:                    SanityManager.ASSERT(hashRowArray != null,
0921:                            "hashRowArray expected to be non-null");
0922:                }
0923:                // Copy out the Object[] without the position.
0924:                DataValueDescriptor[] resultRowArray = new DataValueDescriptor[hashRowArray.length
0925:                        - extraColumns];
0926:                System.arraycopy(hashRowArray, extraColumns, resultRowArray, 0,
0927:                        resultRowArray.length);
0928:
0929:                resultRow.setRowArray(resultRowArray);
0930:
0931:                // Reset the current position to the user position
0932:                currentPosition = position;
0933:
0934:                numFromHashTable++;
0935:
0936:                if (resultRow != null) {
0937:                    beforeFirst = false;
0938:                    afterLast = false;
0939:                }
0940:
0941:                if (isForUpdate()) {
0942:                    RowLocation rowLoc = (RowLocation) hashRowArray[POS_ROWLOCATION];
0943:                    // Keep source and target with the same currentRow
0944:                    ((NoPutResultSet) target).setCurrentRow(resultRow);
0945:                    ((NoPutResultSet) target).positionScanAtRowLocation(rowLoc);
0946:                    needsRepositioning = true;
0947:                }
0948:
0949:                setCurrentRow(resultRow);
0950:
0951:                return resultRow;
0952:            }
0953:
0954:            /**
0955:             * Get the row data at the specified position 
0956:             * from the hash table.
0957:             *
0958:             * @param position	The specified position.
0959:             *
0960:             * @return	The row data at that position.
0961:             *
0962:             * @exception StandardException thrown on failure 
0963:             */
0964:            private DataValueDescriptor[] getRowArrayFromHashTable(int position)
0965:                    throws StandardException {
0966:                positionInHashTable.setValue(position);
0967:                final DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) ht
0968:                        .get(positionInHashTable);
0969:
0970:                // Copy out the Object[] without the position.
0971:                final DataValueDescriptor[] resultRowArray = new DataValueDescriptor[hashRowArray.length
0972:                        - extraColumns];
0973:                System.arraycopy(hashRowArray, extraColumns, resultRowArray, 0,
0974:                        resultRowArray.length);
0975:                return resultRowArray;
0976:            }
0977:
0978:            /**
0979:             * Positions the cursor in the last fetched row. This is done before
0980:             * navigating to a row that has not previously been fetched, so that
0981:             * getNextRowCore() will re-start from where it stopped.
0982:             */
0983:            private void positionInLastFetchedRow() throws StandardException {
0984:                if (positionInSource > 0) {
0985:                    positionInHashTable.setValue(positionInSource);
0986:                    DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) ht
0987:                            .get(positionInHashTable);
0988:                    RowLocation rowLoc = (RowLocation) hashRowArray[POS_ROWLOCATION];
0989:                    ((NoPutResultSet) target).positionScanAtRowLocation(rowLoc);
0990:                    currentPosition = positionInSource;
0991:                }
0992:            }
0993:
0994:            /**
0995:             * @see NoPutResultSet#updateRow
0996:             *
0997:             * Sets the updated column of the hash table to true and updates the row
0998:             * in the hash table with the new values for the row.
0999:             */
1000:            public void updateRow(ExecRow row) throws StandardException {
1001:                ExecRow newRow = row;
1002:                boolean undoProjection = false;
1003:
1004:                if (source instanceof  ProjectRestrictResultSet) {
1005:                    newRow = ((ProjectRestrictResultSet) source)
1006:                            .doBaseRowProjection(row);
1007:                    undoProjection = true;
1008:                }
1009:                positionInHashTable.setValue(currentPosition);
1010:                DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) ht
1011:                        .get(positionInHashTable);
1012:                RowLocation rowLoc = (RowLocation) hashRowArray[POS_ROWLOCATION];
1013:                ht.remove(new SQLInteger(currentPosition));
1014:                addRowToHashTable(newRow, currentPosition, rowLoc, true);
1015:
1016:                // Modify row to refer to data in the BackingStoreHashtable.
1017:                // This allows reading of data which goes over multiple pages
1018:                // when doing the actual update (LOBs). Putting columns of
1019:                // type SQLBinary to disk, has destructive effect on the columns,
1020:                // and they need to be re-read. That is the reason this is needed.
1021:                if (undoProjection) {
1022:
1023:                    final DataValueDescriptor[] newRowData = newRow
1024:                            .getRowArray();
1025:
1026:                    // Array of original position in row
1027:                    final int[] origPos = ((ProjectRestrictResultSet) source)
1028:                            .getBaseProjectMapping();
1029:
1030:                    // We want the row to contain data backed in BackingStoreHashtable
1031:                    final DataValueDescriptor[] backedData = getRowArrayFromHashTable(currentPosition);
1032:
1033:                    for (int i = 0; i < origPos.length; i++) {
1034:                        if (origPos[i] >= 0) {
1035:                            row.setColumn(origPos[i], backedData[i]);
1036:                        }
1037:                    }
1038:                } else {
1039:                    row.setRowArray(getRowArrayFromHashTable(currentPosition));
1040:                }
1041:            }
1042:
1043:            /**
1044:             * @see NoPutResultSet#markRowAsDeleted
1045:             *
1046:             * Sets the deleted column of the hash table to true in the current row.
1047:             */
1048:            public void markRowAsDeleted() throws StandardException {
1049:                positionInHashTable.setValue(currentPosition);
1050:                DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) ht
1051:                        .get(positionInHashTable);
1052:                RowLocation rowLoc = (RowLocation) hashRowArray[POS_ROWLOCATION];
1053:                ht.remove(new SQLInteger(currentPosition));
1054:                ((SQLBoolean) hashRowArray[POS_ROWDELETED]).setValue(true);
1055:                // Set all columns to NULL, the row is now a placeholder
1056:                for (int i = extraColumns; i < hashRowArray.length; i++) {
1057:                    hashRowArray[i].setToNull();
1058:                }
1059:
1060:                ht.put(true, hashRowArray);
1061:            }
1062:
1063:            /**
1064:             * Returns TRUE if the row was been deleted within the transaction,
1065:             * otherwise returns FALSE
1066:             *
1067:             * @return True if the row has been deleted, otherwise false
1068:             *
1069:             * @exception StandardException on error
1070:             */
1071:            public boolean isDeleted() throws StandardException {
1072:                if (currentPosition <= positionInSource && currentPosition > 0) {
1073:                    positionInHashTable.setValue(currentPosition);
1074:                    DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) ht
1075:                            .get(positionInHashTable);
1076:                    return hashRowArray[POS_ROWDELETED].getBoolean();
1077:                }
1078:                return false;
1079:            }
1080:
1081:            /**
1082:             * Returns TRUE if the row was been updated within the transaction,
1083:             * otherwise returns FALSE
1084:             *
1085:             * @return True if the row has been deleted, otherwise false
1086:             *
1087:             * @exception StandardException on error
1088:             */
1089:            public boolean isUpdated() throws StandardException {
1090:                if (currentPosition <= positionInSource && currentPosition > 0) {
1091:                    positionInHashTable.setValue(currentPosition);
1092:                    DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) ht
1093:                            .get(positionInHashTable);
1094:                    return hashRowArray[POS_ROWUPDATED].getBoolean();
1095:                }
1096:                return false;
1097:            }
1098:
1099:            public boolean isForUpdate() {
1100:                return source.isForUpdate();
1101:            }
1102:
1103:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.