| 1 | /* ============================================================= |
| 2 | * SmallSQL : a free Java DBMS library for the Java(tm) platform |
| 3 | * ============================================================= |
| 4 | * |
| 5 | * (C) Copyright 2004-2006, by Volker Berlin. |
| 6 | * |
| 7 | * Project Info: http://www.smallsql.de/ |
| 8 | * |
| 9 | * This library is free software; you can redistribute it and/or modify it |
| 10 | * under the terms of the GNU Lesser General Public License as published by |
| 11 | * the Free Software Foundation; either version 2.1 of the License, or |
| 12 | * (at your option) any later version. |
| 13 | * |
| 14 | * This library is distributed in the hope that it will be useful, but |
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| 17 | * License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU Lesser General Public |
| 20 | * License along with this library; if not, write to the Free Software |
| 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
| 22 | * USA. |
| 23 | * |
| 24 | * [Java is a trademark or registered trademark of Sun Microsystems, Inc. |
| 25 | * in the United States and other countries.] |
| 26 | * |
| 27 | * --------------- |
| 28 | * IndexScrollStatus.java |
| 29 | * --------------- |
| 30 | * Author: Volker Berlin |
| 31 | * |
| 32 | * Created on 18.04.2005 |
| 33 | */ |
| 34 | package smallsql.database; |
| 35 | |
| 36 | /** |
| 37 | * This class save the status of the scrolling through a Index. This is like a Cursor. |
| 38 | */ |
| 39 | class IndexScrollStatus { |
| 40 | private final IndexNode rootPage; |
| 41 | private final Expressions expressions; // is used for the description of ASC and DESC |
| 42 | |
| 43 | private final java.util.Stack nodeStack = new java.util.Stack(); //TODO performance Stack durch nicht synchronisierte Klasse ersetzten |
| 44 | /** Used for getRowOffset() as context cash between 2 calls */ |
| 45 | private LongTreeList longList; |
| 46 | private LongTreeListEnum longListEnum = new LongTreeListEnum(); |
| 47 | |
| 48 | |
| 49 | IndexScrollStatus(IndexNode rootPage, Expressions expressions){ |
| 50 | this.rootPage = rootPage; |
| 51 | this.expressions= expressions; |
| 52 | reset(); |
| 53 | } |
| 54 | |
| 55 | |
| 56 | /** |
| 57 | * Reset this index to start a new scan of it with nextRowoffset() |
| 58 | */ |
| 59 | final void reset(){ |
| 60 | nodeStack.clear(); |
| 61 | boolean asc = (expressions.get(0).getAlias() != SQLTokenizer.DESC_STR); |
| 62 | nodeStack.push( new IndexNodeScrollStatus(rootPage, asc, true, 0) ); |
| 63 | } |
| 64 | |
| 65 | |
| 66 | /** |
| 67 | * Return the next rowOffset of this index. You need to call reset() before the first use. |
| 68 | * @param next if true the next rowOffset else the previous rowOffset |
| 69 | */ |
| 70 | final long getRowOffset( boolean scroll){ |
| 71 | if(longList != null){ |
| 72 | long rowOffset = scroll ? |
| 73 | longList.getNext(longListEnum) : |
| 74 | longList.getPrevious(longListEnum); |
| 75 | if(rowOffset < 0){ |
| 76 | // No more enties on this node |
| 77 | longList = null; |
| 78 | }else{ |
| 79 | return rowOffset; |
| 80 | } |
| 81 | } |
| 82 | while(true){ |
| 83 | IndexNodeScrollStatus status = (IndexNodeScrollStatus)nodeStack.peek(); |
| 84 | int level = status.level; |
| 85 | if(!status.asc ^ scroll){ |
| 86 | //ASC order |
| 87 | int idx = ++status.idx; |
| 88 | if(idx == -1){ |
| 89 | if(status.nodeValue != null){ |
| 90 | if(status.nodeValue instanceof IndexNode){ |
| 91 | level++; |
| 92 | nodeStack.push( |
| 93 | new IndexNodeScrollStatus( (IndexNode)status.nodeValue, |
| 94 | (expressions.get(level).getAlias() != SQLTokenizer.DESC_STR), |
| 95 | scroll, level)); |
| 96 | continue; |
| 97 | }else |
| 98 | return getReturnValue(status.nodeValue); |
| 99 | } |
| 100 | //There is no RowOffset in this node |
| 101 | idx = ++status.idx; |
| 102 | } |
| 103 | if(idx >= status.nodes.length){ |
| 104 | //No more nodes in this level |
| 105 | if(nodeStack.size() > 1){ |
| 106 | nodeStack.pop(); |
| 107 | continue; |
| 108 | }else{ |
| 109 | //No more RowOffsets in this Index |
| 110 | return -1; |
| 111 | } |
| 112 | } |
| 113 | IndexNode node = status.nodes[idx]; |
| 114 | nodeStack.push( new IndexNodeScrollStatus(node, status.asc, scroll, level) ); |
| 115 | }else{ |
| 116 | //DESC order |
| 117 | int idx = --status.idx; |
| 118 | if(idx == -1){ |
| 119 | if(status.nodeValue != null){ |
| 120 | if(status.nodeValue instanceof IndexNode){ |
| 121 | level++; |
| 122 | nodeStack.push( |
| 123 | new IndexNodeScrollStatus( (IndexNode)status.nodeValue, |
| 124 | (expressions.get(level).getAlias() != SQLTokenizer.DESC_STR), |
| 125 | scroll, level)); |
| 126 | continue; |
| 127 | }else |
| 128 | return getReturnValue(status.nodeValue); |
| 129 | } |
| 130 | //There is no RowOffset in this node |
| 131 | } |
| 132 | if(idx < 0){ |
| 133 | //No more nodes in this level |
| 134 | if(nodeStack.size() > 1){ |
| 135 | nodeStack.pop(); |
| 136 | continue; |
| 137 | }else{ |
| 138 | //No more RowOffsets in this Index |
| 139 | return -1; |
| 140 | } |
| 141 | } |
| 142 | IndexNode node = status.nodes[idx]; |
| 143 | nodeStack.push( new IndexNodeScrollStatus(node, status.asc, scroll, level) ); |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | |
| 149 | /** |
| 150 | * Move the index after the last position. The next call nextRowOffset() returns a -1 |
| 151 | * |
| 152 | */ |
| 153 | final void afterLast(){ |
| 154 | longList = null; |
| 155 | nodeStack.setSize(1); |
| 156 | ((IndexNodeScrollStatus)nodeStack.peek()).afterLast(); |
| 157 | } |
| 158 | |
| 159 | |
| 160 | private final long getReturnValue( Object value){ |
| 161 | if(rootPage.getUnique()){ |
| 162 | return ((Long)value).longValue(); |
| 163 | }else{ |
| 164 | longList = (LongTreeList)value; |
| 165 | longListEnum.reset(); |
| 166 | return longList.getNext(longListEnum); // there be should one value as minimum |
| 167 | } |
| 168 | |
| 169 | } |
| 170 | |
| 171 | |
| 172 | |
| 173 | |
| 174 | } |