| 1 package com.quadcap.sql; 2 3 40 41 import java.io.ByteArrayOutputStream ; 42 import java.io.Externalizable ; 43 import java.io.IOException ; 44 import java.io.ObjectInput ; 45 import java.io.ObjectOutput ; 46 47 import java.util.BitSet ; 48 import java.util.Enumeration ; 49 import java.util.Hashtable ; 50 import java.util.Vector ; 51 52 import java.sql.SQLException ; 53 54 import com.quadcap.sql.file.BlockFile; 55 import com.quadcap.sql.file.ByteUtil; 56 import com.quadcap.sql.file.PageManager; 57 import com.quadcap.sql.file.RandomAccess; 58 59 import com.quadcap.sql.io.ObjectOutputStream; 60 61 import com.quadcap.sql.index.BCursor; 62 import com.quadcap.sql.index.Btree; 63 import com.quadcap.sql.index.Comparator; 64 65 import com.quadcap.sql.types.Value; 66 import com.quadcap.sql.types.ValueBoolean; 67 import com.quadcap.sql.types.ValueInteger; 68 import com.quadcap.sql.types.Type; 69 70 import com.quadcap.util.Debug; 71 import com.quadcap.util.Util; 72 73 79 public class JoinInnerCursor extends JoinCursor { 80 Database db; 81 BlockFile file; 82 BlockFile tempFile; 83 84 85 int[] caCols; 86 87 88 byte[] caKey; 89 90 91 int cbCnt; 92 93 94 int[] cbCols; 95 96 97 int[] cbMap; 98 99 100 int[] caMap; 101 102 103 Table cbTable; 104 105 106 IndexConstraint cbIndex; 107 108 109 Btree index; 110 111 112 boolean tempIndex; 113 114 115 boolean mustFreeRows = false; 116 117 BCursor cbKeys; 118 119 120 Comparator compare; 121 122 123 MapRow mapRow; 124 125 140 public JoinInnerCursor(Session session, Cursor outer, Cursor ca, int[] caCols, 141 Cursor cb, int[] cbCols, 142 Expression where, Tuple tuple, JoinMapRow row, 143 boolean left, boolean inner) 144 throws SQLException  145 { 146 super(session, outer, ca, cb, where, tuple, row, left, inner); 147 this.db = session.getDatabase(); 148 this.file = db.getFile(); 149 try { 150 this.tempFile = db.getTempFile(); 151 } catch (IOException e) { 152 throw DbException.wrapThrowable(e); 153 } 154 this.caCols = caCols; 155 this.cbCnt = cb.getColumnCount(); 156 this.cbCols = cbCols; 157 this.cbIndex = findIndex(cb, cbCols); 158 this.compare = new Key(cbCols.length); 159 160 int joinCnt = cbCols.length; 161 162 } 163 164 final IndexConstraint findIndex(Cursor r, int[] cols) 165 throws SQLException 166 { 167 IndexConstraint ret = null; 168 BitSet b = null; 169 this.cbTable = r.getTable(); 170 if (this.cbTable == null) { 171 return null; 172 } 173 final int num = cbTable.getNumConstraints(); 174 for (int ci = 0; ci < num; ci++) { 175 Constraint c = cbTable.getConstraint(ci); 176 if (!(c instanceof IndexConstraint)) continue; 177 int[] ccols = c.getColumns(); 178 if (cols.length != ccols.length) continue; 179 if (b == null) b = intArrayToBitSet(cols); 180 boolean match = true; 181 for (int i = 0; i < ccols.length; i++) { 182 if (!b.get(ccols[i])) { 183 match = false; 184 break; 185 } 186 } 187 if (match) ret = (IndexConstraint)c; 188 } 189 return ret; 190 } 191 192 final static BitSet intArrayToBitSet(int[] a) { 193 BitSet b = new BitSet (); 194 for (int i = 0; i < a.length; i++) { 195 b.set(a[i]); 196 } 197 return b; 198 } 199 200 final byte[] makeInnerKey(Cursor cursor, Row row, long rowId) 201 throws IOException , SQLException  202 { 203 return Key.makeKey(cursor, row, cbCols, rowId, true); 204 } 205 206 final byte[] makeOuterKey(Cursor cursor, Row row) 207 throws IOException , SQLException  208 { 209 if (cbIndex != null) { 210 mapRow.setRow(row); 211 return cbIndex.makeKey(session, mapRow, Long.MIN_VALUE); 212 } 213 return Key.makeKey(cursor, row, caCols, Long.MIN_VALUE, 214 true); 215 } 216 217 218 protected void bfirst() throws SQLException { 219 try { 220 row.setB(null); 221 if (index == null) { 222 this.index = makeInnerIndex(); 223 this.rb = new LazyRow(cbCnt); 224 } 225 caKey = makeOuterKey(ca, ra); 226 if (cbKeys == null) cbKeys = index.getCursor(false); 227 cbKeys.seek(caKey); 228 } catch (IOException e) { 229 throw DbException.wrapThrowable(e); 230 } 231 } 232 233 final protected boolean bnext() throws SQLException { 234 try { 235 boolean ret = false; 236 237 while (!ret && cbKeys.next()) { 238 byte[] cbKey = cbKeys.getKeyBuf(); 239 int len = cbKeys.getKeyLen(); 240 if (compare.compare(caKey, 0, caKey.length, 241 cbKey, 0, len) != 0) { 242 break; 243 } 244 long rowId = cbKeys.getValAsLong(); 245 boolean isTemp = cbTable == null; 246 db.getRow(rowId, (LazyRow)rb, isTemp); 247 row.setB(rb); 248 ret = true; 250 } 251 if (!ret) row.setB(null); 252 return ret; 253 } catch (IOException ex) { 254 throw DbException.wrapThrowable(ex); 255 } 256 } 257 258 final void makeTemporaryIndexForTable() throws IOException , SQLException { 259 if (Trace.bit(17)) { 261 StringBuffer sb = new StringBuffer (); 262 for (int i = 0; i < cbCols.length; i++) { 263 if (i > 0) sb.append(", "); 264 sb.append(cb.getColumn(cbCols[i]).getName()); 265 } 266 Debug.println("Make Temporary Index for " + cb.getName() + 267 " (" + sb + ")"); 268 } 269 Comparator tempCompare = new Key(cbCols.length + 1); 271 index = session.makeTempTree(tempCompare); 272 while (cb.next()) { 273 long rowId = cb.getRowId(); 274 Row r = cb.getRow(); 275 byte[] key = makeInnerKey(cb, r, rowId); 276 index.set(key, session.getBuf8(rowId)); 277 } 278 } 279 280 final void makeTemporaryIndexForView() throws IOException , SQLException { 281 Comparator tempCompare = new Key(cbCols.length + 1); 282 index = session.makeTempTree(tempCompare); 283 int cnt = 0; 284 mustFreeRows = true; 285 while (cb.next()) { 286 Row r = cb.getRow(); 287 byte[] key = makeInnerKey(cb, r, cnt++); 288 long rowId = session.getDatabase().putRow(session, tempFile, cb, r); 289 index.set(key, session.getBuf8(rowId)); 290 } 291 } 292 293 final Btree makeInnerIndex() throws IOException , SQLException { 294 if (cbTable != null) { 295 if (cbIndex != null) { 296 int[] map = new int[cb.getColumnCount() + 1]; 297 for (int i = 0; i < cbCols.length; i++) { 298 int ic = cbCols[i]; 299 int oc = caCols[i]; 300 map[ic] = oc; 301 } 302 mapRow = new MapRow(map, 1); 303 index = cbIndex.getIndex(db); 304 } else { 305 makeTemporaryIndexForTable(); 306 tempIndex = true; 307 } 308 } else { 309 makeTemporaryIndexForView(); 310 tempIndex = true; 311 } 312 return index; 313 } 314 315 public void freeRows(Btree index, BlockFile file) 316 throws IOException 317 { 318 BCursor c = index.getCursor(); 319 try { 320 while (c.next()) { 321 long rowId = c.getValAsLong(); 322 db.removeRow(file, rowId); 323 } 324 } finally { 325 c.release(); 326 } 327 } 328 329 public void close() throws SQLException { 330 try { 331 super.close(); 332 } finally { 333 try { 334 if (cbKeys != null) cbKeys.release(); 335 } finally { 336 try { 337 cbKeys = null; 338 if (tempIndex && mustFreeRows) { 339 freeRows(index, tempFile); 340 } 341 } catch (IOException e2) { 342 throw DbException.wrapThrowable(e2); 343 } finally { 344 try { 345 mustFreeRows = false; 346 if (tempIndex) { 347 index.free(); 348 session.getDatabase().releaseTempFile(); 349 } 350 } catch (IOException e3) { 351 throw DbException.wrapThrowable(e3); 352 } finally { 353 index = null; 354 if (tempFile != null) { 355 session.getDatabase().releaseTempFile(); 356 tempFile = null; 357 } 358 tempIndex = false; 359 } 360 } 361 } 362 } 363 } 364 } 365 | Popular Tags |