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 | * TableResult.java |
29 | * --------------- |
30 | * Author: Volker Berlin |
31 | * |
32 | */ |
33 | package smallsql.database; |
34 | |
35 | import java.sql.*; |
36 | import java.util.List; |
37 | |
38 | |
39 | final class TableResult extends TableViewResult{ |
40 | |
41 | final private Table table; |
42 | /** A List of rows that was inserted. The rows can be uncommited in memory or commited on harddisk. |
43 | * The WHERE condition does not need to be valid. |
44 | */ |
45 | private List insertStorePages; |
46 | /** |
47 | * The filePos of the first own insert with insertRow(). On this rows the WHERE condition is not verify. |
48 | */ |
49 | private long firstOwnInsert; |
50 | /** |
51 | * The max fileOffset at open the ResultSet. Rows that are commited later are not not counted. |
52 | */ |
53 | private long maxFileOffset; |
54 | |
55 | TableResult(Table table){ |
56 | this.table = table; |
57 | } |
58 | |
59 | |
60 | /** |
61 | * Is used for compile() of different Commands |
62 | * |
63 | * @param con |
64 | * @return true if now init; false if allready init |
65 | * @throws Exception |
66 | */ |
67 | final boolean init( SSConnection con ) throws Exception{ |
68 | if(super.init(con)){ |
69 | Columns columns = table.columns; |
70 | offsets = new int[columns.size()]; |
71 | dataTypes = new int[columns.size()]; |
72 | for(int i=0; i<columns.size(); i++){ |
73 | dataTypes[i] = columns.get(i).getDataType(); |
74 | } |
75 | return true; |
76 | } |
77 | return false; |
78 | } |
79 | |
80 | |
81 | final void execute() throws Exception{ |
82 | insertStorePages = table.getInserts(con); |
83 | firstOwnInsert = 0x4000000000000000L | insertStorePages.size(); |
84 | maxFileOffset = table.raFile.length(); |
85 | beforeFirst(); |
86 | } |
87 | |
88 | /*============================================================================== |
89 | |
90 | Methods for base class TableViewResult |
91 | |
92 | ==============================================================================*/ |
93 | |
94 | final TableView getTableView(){ |
95 | return table; |
96 | } |
97 | |
98 | |
99 | |
100 | final void deleteRow() throws SQLException{ |
101 | store.deleteRow(con); |
102 | store = new StoreNull(store.getNextPagePos()); |
103 | } |
104 | |
105 | |
106 | final void updateRow(Expression[] updateValues) throws Exception{ |
107 | Columns tableColumns = table.columns; |
108 | int count = tableColumns.size(); |
109 | |
110 | |
111 | StoreImpl newStore = table.getStoreTemp(con); |
112 | for(int i=0; i<count; i++){ |
113 | Expression src = updateValues[i]; |
114 | if(src != null){ |
115 | newStore.writeExpression( src, tableColumns.get(i) ); |
116 | }else{ |
117 | copyValueInto( i, newStore ); |
118 | } |
119 | } |
120 | ((StoreImpl)this.store).updateFinsh(con, newStore); |
121 | } |
122 | |
123 | |
124 | final void insertRow(Expression[] updateValues) throws Exception{ |
125 | Columns tableColumns = table.columns; |
126 | int count = tableColumns.size(); |
127 | |
128 | // save the new values if there are new value for this table |
129 | StoreImpl store = table.getStoreInsert(con); |
130 | for(int i=0; i<count; i++){ |
131 | Column tableColumn = tableColumns.get(i); |
132 | Expression src = updateValues[i]; |
133 | if(src == null) src = tableColumn.getDefaultValue(con); |
134 | store.writeExpression( src, tableColumn ); |
135 | |
136 | } |
137 | store.writeFinsh( con ); |
138 | insertStorePages.add(store.getLink()); |
139 | } |
140 | |
141 | |
142 | /*============================================================================== |
143 | |
144 | Methods for Interface RowSource |
145 | |
146 | ==============================================================================*/ |
147 | private Store store = Store.NOROW; |
148 | |
149 | /** The row position in the file of the table. */ |
150 | private long filePos; |
151 | private int[] offsets; |
152 | private int[] dataTypes; |
153 | private int row; |
154 | |
155 | |
156 | /** |
157 | * Move to the row in the filePos. A value of -1 for filePos is invalid at this call point. |
158 | */ |
159 | final private boolean moveToRow() throws Exception{ |
160 | if(filePos >= 0x4000000000000000L){ |
161 | store = ((StorePageLink)insertStorePages.get( (int)(filePos & 0x3FFFFFFFFFFFFFFFL) )).getStore( table, con, lock); |
162 | }else{ |
163 | store = (filePos < maxFileOffset) ? table.getStore( con, filePos, lock ) : null; |
164 | if(store == null){ |
165 | if(insertStorePages.size() > 0){ |
166 | filePos = 0x4000000000000000L; |
167 | store = ((StorePageLink)insertStorePages.get( (int)(filePos & 0x3FFFFFFFFFFFFFFFL) )).getStore( table, con, lock); |
168 | } |
169 | } |
170 | } |
171 | if(store != null){ |
172 | if(!store.isValidPage()){ |
173 | return false; |
174 | } |
175 | store.scanObjectOffsets( offsets, dataTypes ); |
176 | return true; |
177 | }else{ |
178 | filePos = -1; |
179 | noRow(); |
180 | return false; |
181 | } |
182 | } |
183 | |
184 | |
185 | /** |
186 | * Move to the next valid row. A valid row is a normal row or an pointer to an updated row value. |
187 | * A invalid row is a deleted row or an updated value that is reference by an update pointer. |
188 | */ |
189 | final private boolean moveToValidRow() throws Exception{ |
190 | while(filePos >= 0){ |
191 | if(moveToRow()) |
192 | return true; |
193 | setNextFilePos(); |
194 | } |
195 | row = 0; |
196 | return false; |
197 | } |
198 | |
199 | |
200 | final void beforeFirst(){ |
201 | filePos = 0; |
202 | store = Store.NOROW; |
203 | row = 0; |
204 | } |
205 | |
206 | |
207 | final boolean first() throws Exception{ |
208 | filePos = table.getFirstPage(); |
209 | row = 1; |
210 | return moveToValidRow(); |
211 | } |
212 | |
213 | |
214 | /** |
215 | * A negative filePos means no more rows.<p> |
216 | * A value larger 0x4000000000000000L means a row that was inserted in this ResultSet.<p> |
217 | * A value of 0 means beforeFirst.<p> |
218 | * All other values are read position in the file.<p> |
219 | * |
220 | */ |
221 | final private void setNextFilePos(){ |
222 | if(filePos < 0) return; // end of rows |
223 | if(store == Store.NOROW) |
224 | filePos = table.getFirstPage(); // can point at the end of file |
225 | else |
226 | if(filePos >= 0x4000000000000000L){ |
227 | filePos++; |
228 | if((filePos & 0x3FFFFFFFFFFFFFFFL) >= insertStorePages.size()){ |
229 | filePos = -1; |
230 | noRow(); |
231 | } |
232 | }else |
233 | filePos = store.getNextPagePos(); |
234 | } |
235 | |
236 | final boolean next() throws Exception{ |
237 | if(filePos < 0) return false; |
238 | setNextFilePos(); |
239 | row++; |
240 | return moveToValidRow(); |
241 | } |
242 | |
243 | |
244 | final void afterLast(){ |
245 | filePos = -1; |
246 | noRow(); |
247 | } |
248 | |
249 | |
250 | final int getRow(){ |
251 | return row; |
252 | } |
253 | |
254 | |
255 | /** |
256 | * Get the position of the row in the file. This is equals to the rowOffset. |
257 | */ |
258 | final long getRowPosition(){ |
259 | return filePos; |
260 | } |
261 | |
262 | |
263 | final void setRowPosition(long rowPosition) throws Exception{ |
264 | filePos = rowPosition; |
265 | if(filePos < 0 || !moveToRow()){ |
266 | store = new StoreNull(store.getNextPagePos()); |
267 | } |
268 | } |
269 | |
270 | |
271 | final boolean rowInserted(){ |
272 | return filePos >= firstOwnInsert; |
273 | } |
274 | |
275 | |
276 | final boolean rowDeleted(){ |
277 | // A StoreNull is created on setRowPosition on a deleted row |
278 | return store instanceof StoreNull && store != Store.NULL; |
279 | } |
280 | |
281 | |
282 | final void nullRow(){ |
283 | row = 0; |
284 | store = Store.NULL; |
285 | } |
286 | |
287 | |
288 | final void noRow(){ |
289 | row = 0; |
290 | store = Store.NOROW; |
291 | } |
292 | |
293 | |
294 | /*======================================================================= |
295 | |
296 | Methods for Data Access |
297 | |
298 | =======================================================================*/ |
299 | |
300 | final boolean isNull( int colIdx ) throws Exception{ |
301 | return store.isNull( offsets[colIdx] ); |
302 | } |
303 | |
304 | final boolean getBoolean( int colIdx ) throws Exception{ |
305 | return store.getBoolean( offsets[colIdx], dataTypes[colIdx] ); |
306 | } |
307 | |
308 | final int getInt( int colIdx ) throws Exception{ |
309 | return store.getInt( offsets[colIdx], dataTypes[colIdx] ); |
310 | } |
311 | |
312 | final long getLong( int colIdx ) throws Exception{ |
313 | return store.getLong( offsets[colIdx], dataTypes[colIdx] ); |
314 | } |
315 | |
316 | final float getFloat( int colIdx ) throws Exception{ |
317 | return store.getFloat( offsets[colIdx], dataTypes[colIdx] ); |
318 | } |
319 | |
320 | final double getDouble( int colIdx ) throws Exception{ |
321 | return store.getDouble( offsets[colIdx], dataTypes[colIdx] ); |
322 | } |
323 | |
324 | final long getMoney( int colIdx ) throws Exception{ |
325 | return store.getMoney( offsets[colIdx], dataTypes[colIdx] ); |
326 | } |
327 | |
328 | final MutableNumeric getNumeric( int colIdx ) throws Exception{ |
329 | return store.getNumeric( offsets[colIdx], dataTypes[colIdx] ); |
330 | } |
331 | |
332 | final Object getObject( int colIdx ) throws Exception{ |
333 | return store.getObject( offsets[colIdx], dataTypes[colIdx] ); |
334 | } |
335 | |
336 | final String getString( int colIdx ) throws Exception{ |
337 | return store.getString( offsets[colIdx], dataTypes[colIdx] ); |
338 | } |
339 | |
340 | final byte[] getBytes( int colIdx ) throws Exception{ |
341 | return store.getBytes( offsets[colIdx], dataTypes[colIdx] ); |
342 | } |
343 | |
344 | final int getDataType( int colIdx ){ |
345 | return dataTypes[colIdx]; |
346 | } |
347 | |
348 | final private void copyValueInto( int colIdx, StoreImpl dst){ |
349 | int offset = offsets[colIdx++]; |
350 | int length = (colIdx < offsets.length ? offsets[colIdx] : store.getUsedSize()) - offset; |
351 | dst.copyValueFrom( (StoreImpl)store, offset, length); |
352 | } |
353 | |
354 | |
355 | } |