00001
package com.quadcap.sql;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.ByteArrayOutputStream;
00042
import java.io.Externalizable;
00043
import java.io.IOException;
00044
import java.io.ObjectInput;
00045
import java.io.ObjectOutput;
00046
00047
import java.util.BitSet;
00048
import java.util.Enumeration;
00049
import java.util.Hashtable;
00050
import java.util.Vector;
00051
00052
import java.sql.SQLException;
00053
00054
import com.quadcap.sql.file.BlockFile;
00055
import com.quadcap.sql.file.ByteUtil;
00056
import com.quadcap.sql.file.PageManager;
00057
import com.quadcap.sql.file.RandomAccess;
00058
00059
import com.quadcap.sql.io.ObjectOutputStream;
00060
00061
import com.quadcap.sql.index.BCursor;
00062
import com.quadcap.sql.index.Btree;
00063
import com.quadcap.sql.index.Comparator;
00064
00065
import com.quadcap.sql.types.Value;
00066
import com.quadcap.sql.types.ValueBoolean;
00067
import com.quadcap.sql.types.ValueInteger;
00068
import com.quadcap.sql.types.Type;
00069
00070
import com.quadcap.util.Debug;
00071
import com.quadcap.util.Util;
00072
00073
00074
00075
00076
00077
00078
00079 public class JoinInnerCursor extends JoinCursor {
00080 Database db;
00081 BlockFile
file;
00082 BlockFile
tempFile;
00083
00084
00085 int[]
caCols;
00086
00087
00088 byte[]
caKey;
00089
00090
00091 int cbCnt;
00092
00093
00094 int[]
cbCols;
00095
00096
00097 int[]
cbMap;
00098
00099
00100 int[]
caMap;
00101
00102
00103 Table cbTable;
00104
00105
00106 IndexConstraint cbIndex;
00107
00108
00109 Btree
index;
00110
00111
00112 boolean tempIndex;
00113
00114
00115 boolean mustFreeRows =
false;
00116
00117 BCursor
cbKeys;
00118
00119
00120 Comparator
compare;
00121
00122
00123 MapRow mapRow;
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 public JoinInnerCursor(
Session session,
Cursor outer,
Cursor ca,
int[] caCols,
00141
Cursor cb,
int[] cbCols,
00142
Expression where,
Tuple tuple,
JoinMapRow row,
00143
boolean left,
boolean inner)
00144
throws SQLException
00145 {
00146 super(session, outer, ca, cb, where, tuple, row, left, inner);
00147
this.db = session.
getDatabase();
00148
this.file =
db.getFile();
00149
try {
00150
this.tempFile =
db.getTempFile();
00151 }
catch (IOException e) {
00152
throw DbException.wrapThrowable(e);
00153 }
00154
this.caCols =
caCols;
00155
this.cbCnt = cb.
getColumnCount();
00156
this.cbCols =
cbCols;
00157
this.cbIndex =
findIndex(cb,
cbCols);
00158
this.compare =
new Key(
cbCols.length);
00159
00160
int joinCnt =
cbCols.length;
00161
00162 }
00163
00164 final IndexConstraint findIndex(
Cursor r,
int[] cols)
00165
throws SQLException
00166 {
00167
IndexConstraint ret = null;
00168 BitSet b = null;
00169
this.cbTable = r.
getTable();
00170
if (
this.cbTable == null) {
00171
return null;
00172 }
00173
final int num =
cbTable.
getNumConstraints();
00174
for (
int ci = 0; ci < num; ci++) {
00175
Constraint c =
cbTable.
getConstraint(ci);
00176
if (!(c instanceof
IndexConstraint))
continue;
00177
int[] ccols = c.
getColumns();
00178
if (cols.length != ccols.length)
continue;
00179
if (b == null) b =
intArrayToBitSet(cols);
00180
boolean match =
true;
00181
for (
int i = 0; i < ccols.length; i++) {
00182
if (!b.get(ccols[i])) {
00183 match =
false;
00184
break;
00185 }
00186 }
00187
if (match) ret = (
IndexConstraint)c;
00188 }
00189
return ret;
00190 }
00191
00192 final static BitSet
intArrayToBitSet(
int[] a) {
00193 BitSet b =
new BitSet();
00194
for (
int i = 0; i < a.length; i++) {
00195 b.set(a[i]);
00196 }
00197
return b;
00198 }
00199
00200 final byte[]
makeInnerKey(
Cursor cursor,
Row row,
long rowId)
00201
throws IOException, SQLException
00202 {
00203
return Key.makeKey(cursor, row,
cbCols, rowId,
true);
00204 }
00205
00206 final byte[]
makeOuterKey(
Cursor cursor,
Row row)
00207
throws IOException, SQLException
00208 {
00209
if (
cbIndex != null) {
00210
mapRow.
setRow(row);
00211
return cbIndex.
makeKey(session,
mapRow, Long.MIN_VALUE);
00212 }
00213
return Key.makeKey(cursor, row,
caCols, Long.MIN_VALUE,
00214
true);
00215 }
00216
00217
00218 protected void bfirst() throws SQLException {
00219
try {
00220 row.
setB(null);
00221
if (
index == null) {
00222
this.index =
makeInnerIndex();
00223
this.rb =
new LazyRow(
cbCnt);
00224 }
00225
caKey = makeOuterKey(ca, ra);
00226
if (
cbKeys == null)
cbKeys =
index.getCursor(
false);
00227
cbKeys.seek(
caKey);
00228 }
catch (IOException e) {
00229
throw DbException.wrapThrowable(e);
00230 }
00231 }
00232
00233 final protected boolean bnext() throws SQLException {
00234
try {
00235
boolean ret =
false;
00236
00237
while (!ret &&
cbKeys.next()) {
00238 byte[] cbKey =
cbKeys.getKeyBuf();
00239
int len =
cbKeys.getKeyLen();
00240
if (
compare.compare(
caKey, 0,
caKey.length,
00241 cbKey, 0, len) != 0) {
00242
break;
00243 }
00244
long rowId =
cbKeys.getValAsLong();
00245
boolean isTemp =
cbTable == null;
00246
db.
getRow(rowId, (
LazyRow)rb, isTemp);
00247 row.
setB(rb);
00248
00249 ret =
true;
00250 }
00251
if (!ret) row.
setB(null);
00252
return ret;
00253 }
catch (IOException ex) {
00254
throw DbException.wrapThrowable(ex);
00255 }
00256 }
00257
00258 final void makeTemporaryIndexForTable() throws IOException, SQLException {
00259
00260
if (
Trace.bit(17)) {
00261 StringBuffer sb =
new StringBuffer();
00262
for (
int i = 0; i <
cbCols.length; i++) {
00263
if (i > 0) sb.append(
", ");
00264 sb.append(cb.
getColumn(
cbCols[i]).
getName());
00265 }
00266
Debug.println(
"Make Temporary Index for " + cb.
getName() +
00267
" (" + sb +
")");
00268 }
00269
00270 Comparator tempCompare =
new Key(
cbCols.length + 1);
00271
index = session.
makeTempTree(tempCompare);
00272
while (cb.
next()) {
00273
long rowId = cb.
getRowId();
00274
Row r = cb.
getRow();
00275 byte[] key = makeInnerKey(cb, r, rowId);
00276
index.set(key, session.
getBuf8(rowId));
00277 }
00278 }
00279
00280 final void makeTemporaryIndexForView() throws IOException, SQLException {
00281 Comparator tempCompare =
new Key(
cbCols.length + 1);
00282
index = session.
makeTempTree(tempCompare);
00283
int cnt = 0;
00284
mustFreeRows =
true;
00285
while (cb.
next()) {
00286
Row r = cb.
getRow();
00287 byte[] key = makeInnerKey(cb, r, cnt++);
00288
long rowId = session.
getDatabase().
putRow(session,
tempFile, cb, r);
00289
index.set(key, session.
getBuf8(rowId));
00290 }
00291 }
00292
00293 final Btree
makeInnerIndex() throws IOException, SQLException {
00294
if (
cbTable != null) {
00295
if (
cbIndex != null) {
00296
int[] map =
new int[cb.
getColumnCount() + 1];
00297
for (
int i = 0; i <
cbCols.length; i++) {
00298
int ic =
cbCols[i];
00299
int oc =
caCols[i];
00300 map[ic] = oc;
00301 }
00302
mapRow =
new MapRow(map, 1);
00303
index =
cbIndex.
getIndex(
db);
00304 }
else {
00305
makeTemporaryIndexForTable();
00306
tempIndex =
true;
00307 }
00308 }
else {
00309
makeTemporaryIndexForView();
00310
tempIndex =
true;
00311 }
00312
return index;
00313 }
00314
00315 public void freeRows(Btree index, BlockFile file)
00316
throws IOException
00317 {
00318 BCursor c =
index.getCursor();
00319
try {
00320
while (c.next()) {
00321
long rowId = c.getValAsLong();
00322
db.
removeRow(
file, rowId);
00323 }
00324 } finally {
00325 c.release();
00326 }
00327 }
00328
00329 public void close() throws SQLException {
00330
try {
00331 super.close();
00332 } finally {
00333
try {
00334
if (
cbKeys != null)
cbKeys.release();
00335 } finally {
00336
try {
00337
cbKeys = null;
00338
if (
tempIndex &&
mustFreeRows) {
00339 freeRows(
index,
tempFile);
00340 }
00341 }
catch (IOException e2) {
00342
throw DbException.wrapThrowable(e2);
00343 } finally {
00344
try {
00345
mustFreeRows =
false;
00346
if (
tempIndex) {
00347
index.free();
00348 session.
getDatabase().releaseTempFile();
00349 }
00350 }
catch (IOException e3) {
00351
throw DbException.wrapThrowable(e3);
00352 } finally {
00353
index = null;
00354
if (
tempFile != null) {
00355 session.
getDatabase().releaseTempFile();
00356
tempFile = null;
00357 }
00358
tempIndex =
false;
00359 }
00360 }
00361 }
00362 }
00363 }
00364 }