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.IOException;
00043
import java.io.ObjectInput;
00044
import java.io.ObjectOutput;
00045
00046
import java.util.Enumeration;
00047
import java.util.Hashtable;
00048
import java.util.Vector;
00049
00050
import java.sql.SQLException;
00051
00052
import com.quadcap.sql.io.ObjectOutputStream;
00053
00054
import com.quadcap.sql.file.ByteUtil;
00055
00056
import com.quadcap.sql.index.Btree;
00057
import com.quadcap.sql.index.Comparator;
00058
00059
import com.quadcap.sql.types.Op;
00060
import com.quadcap.sql.types.Value;
00061
import com.quadcap.sql.types.ValueException;
00062
import com.quadcap.sql.types.ValueInteger;
00063
import com.quadcap.sql.types.ValueNull;
00064
00065
import com.quadcap.util.Debug;
00066
import com.quadcap.util.Util;
00067
00068
00069
00070
00071
00072
00073 public class IndexCursor extends BC_Cursor {
00074 Table table;
00075 IndexConstraint constraint;
00076 Btree
index;
00077 Comparator
compare;
00078 Vector
indexNames = null;
00079 StaticCursor startVals = null;
00080 StaticCursor stopVals = null;
00081
00082 byte[]
startVal;
00083 byte[]
stopVal;
00084
00085
00086
00087
00088
00089
00090 public IndexCursor(
Table table,
Session session,
00091
IndexConstraint constraint,
Expression where,
00092 String qualifier,
Cursor outerCursor)
00093
throws SQLException, IOException
00094 {
00095 super(session, qualifier, outerCursor);
00096
this.table =
table;
00097
this.constraint =
constraint;
00098
this.
index =
constraint.
getIndex(session.
getDatabase());
00099
this.compare =
index.getComparator();
00100
00101 addColumns(session,
table);
00102
00103
this.indexNames =
constraint.
getColumnNames();
00104
reset(where, outerCursor);
00105 }
00106 public void checkCursor() throws SQLException {
00107
if (bc == null) {
00108
throw new SQLException(
"Cursor closed");
00109 }
00110 }
00111
00112 public long getCurrentRowId() throws SQLException {
00113
checkCursor();
00114
return ByteUtil.getLong(bc.
getValBuf(), 0);
00115 }
00116
00117 public void fetchCurrentRow() throws SQLException, IOException {
00118 session.
getDatabase().
getRow(rowId, row,
false);
00119 rowValid =
true;
00120 }
00121
00122 public IndexConstraint getConstraint() {
00123
return constraint;
00124 }
00125
00126 public void reset(
Expression where,
Cursor outer)
00127
throws SQLException
00128 {
00129
try {
00130
this.setOuterCursor(outer);
00131
startVal = null;
00132
stopVal = null;
00133
if (
indexNames != null &&
indexNames.size() > 0) {
00134
startVals =
makeValues(session,
table,
ValueNull.valueNull);
00135
stopVals = makeValues(session,
table,
ValueNull.valueLastNull);
00136
getCursorRange(session, where,
startVals,
stopVals);
00137
startVal =
constraint.
makeKey(session,
startVals.
getRow(),
00138 Long.MIN_VALUE);
00139
stopVal =
constraint.
makeKey(session,
stopVals.
getRow(),
00140 Long.MAX_VALUE);
00141
00142
00143 }
00144
00145
this.row =
new LazyRow(
table.
getColumnCount());
00146 bc =
index.getCursor(
false);
00147
if (
startVal != null) {
00148 bc.
seek(
startVal);
00149 }
else {
00150 bc.
beforeFirst();
00151 }
00152 }
catch (IOException e) {
00153
throw DbException.wrapThrowable(e);
00154 }
00155 }
00156
00157
00158
00159
00160
00161 StaticCursor makeValues(
Session session,
Table table,
Value v)
00162
throws SQLException
00163 {
00164
Row r =
new Row(
table.
getColumnCount());
00165
for (
int i = 1; i <= r.
size(); i++) {
00166 r.
set(i, v);
00167 }
00168
StaticCursor s =
new StaticCursor(session,
table, r);
00169 s.
absolute(1);
00170
return s;
00171 }
00172
00173
00174 static String
isa(Object x) {
00175
return x == null ?
"null" :
00176 x.getClass().
getName() +
":" + x;
00177 }
00178
00179
00180
00181
00182
00183
00184 void getCursorRange(
Session session,
Expression e,
00185
StaticCursor startVals,
StaticCursor stopVals)
00186
throws SQLException
00187 {
00188
if (e instanceof
BinaryExpression) {
00189
BinaryExpression b = (
BinaryExpression)e;
00190
switch (b.
op) {
00191
case Op.EQ:
00192
00193
00194
00195
if (b.
e instanceof
NameExpression) {
00196
NameExpression ne = (
NameExpression)b.
e;
00197 String name = session.
getConnection().
resolveColname(ne.
getName(),
table);
00198 String tname =
table.
getName();
00199
if (name.startsWith(tname)) name = name.substring(tname.length() + 1);
00200
00201
if (
startVals.
get(name) != null) {
00202
try {
00203
Value v = b.
f.
getValue(session, outer);
00204
00205
startVals.
put(name, v);
00206
stopVals.
put(name, v);
00207
return;
00208 }
catch (SQLException se) {}
00209 }
00210 }
00211
if (b.
f instanceof
NameExpression) {
00212
NameExpression nf = (
NameExpression)b.
f;
00213 String name = session.
getConnection().
resolveColname(nf.
getName(),
table);
00214
if (
startVals.
get(name) != null) {
00215
try {
00216
Value v = b.
e.
getValue(session, outer);
00217
startVals.
put(name, v);
00218
stopVals.
put(name, v);
00219 }
catch (SQLException se) {}
00220 }
00221 }
00222
break;
00223
case Op.AND:
00224 getCursorRange(session, b.
e,
startVals,
stopVals);
00225 getCursorRange(session, b.
f,
startVals,
stopVals);
00226
break;
00227
case Op.LT:
00228
case Op.LE:
00229
doOneBound(session, b.
e, b.
f,
startVals,
stopVals);
00230
break;
00231
case Op.GT:
00232
case Op.GE:
00233
doOneBound(session, b.
f, b.
e,
startVals,
stopVals);
00234
break;
00235 }
00236 }
else if (e instanceof
TernaryExpression) {
00237
TernaryExpression t = (
TernaryExpression)e;
00238
if (t.
op ==
Op.BETWEEN) {
00239
if (!t.
not) {
00240
doOneBound(session, t.
f, t.
e,
startVals,
stopVals);
00241
doOneBound(session, t.
e, t.
g,
startVals,
stopVals);
00242 }
00243 }
00244 }
00245 }
00246
00247
00248
00249
00250
00251 void doOneBound(
Session session,
Expression a,
Expression b,
00252
StaticCursor startVals,
StaticCursor stopVals)
00253
throws SQLException
00254 {
00255
if (a instanceof
NameExpression) {
00256
NameExpression na = (
NameExpression)a;
00257 String name = na.
getName();
00258
Value s = (
Value)
stopVals.
get(name);
00259
if (s != null) {
00260
Value v = b.getValue(session, null);
00261
Value cmp =
Value.binop(
Op.COMPARE, v, s);
00262
ValueInteger vi = (
ValueInteger)cmp;
00263
int ret = vi.
intValue();
00264
if (ret < 0) {
00265
stopVals.
put(name, v);
00266 }
00267 }
00268 }
else if (b instanceof
NameExpression) {
00269
NameExpression nb = (
NameExpression)b;
00270 String name = nb.
getName();
00271
Value s = (
Value)
startVals.
get(name);
00272
if (s != null) {
00273
Value v = a.getValue(session, null);
00274
Value cmp =
Value.binop(
Op.COMPARE, v, s);
00275
ValueInteger vi = (
ValueInteger)cmp;
00276
int ret = vi.
intValue();
00277
if (ret > 0) {
00278
startVals.
put(name, v);
00279 }
00280 }
00281 }
00282 }
00283
00284
00285
00286
00287 public boolean next() throws SQLException {
00288
boolean ret = super.next();
00289
if (ret) {
00290
if (
stopVal != null) {
00291
if (
compare.compare(bc.
getKeyBuf(), 0, bc.
getKeyLen(),
00292
stopVal, 0,
stopVal.length) > 0) {
00293 ret =
false;
00294 }
00295 }
00296 }
00297
return ret;
00298 }
00299
00300
00301
00302
00303 public boolean prev() throws SQLException {
00304
boolean ret = super.prev();
00305
if (ret) {
00306
if (
startVal != null) {
00307
if (
compare.compare(bc.
getKeyBuf(), 0, bc.
getKeyLen(),
00308
startVal, 0,
startVal.length) < 0) {
00309 ret =
false;
00310 }
00311 }
00312 }
00313
return ret;
00314 }
00315
00316
00317
00318
00319 public void updateRow(
Row row)
throws SQLException {
00320
try {
00321
TableOps.updateRow(session,
table,
00322 bc.
getKey(), rowId,
00323 row,
constraint);
00324 }
catch (IOException e) {
00325
throw DbException.wrapThrowable(e);
00326 }
00327 }
00328
00329
00330
00331
00332 public void insertRow(
Row row)
throws SQLException {
00333
try {
00334
TableOps.insertRow(session,
table, row);
00335 }
catch (IOException e) {
00336
throw DbException.wrapThrowable(e);
00337 }
00338 }
00339
00340
00341
00342
00343 public void deleteRow() throws SQLException {
00344
try {
00345
TableOps.deleteRow(session,
table,
00346 rowId,
getRow(),
constraint);
00347 }
catch (IOException e) {
00348
throw DbException.wrapThrowable(e);
00349 }
00350 }
00351
00352
00353
00354
00355 public void beforeFirst() throws SQLException {
00356
try {
00357 rowValid =
false;
00358 rowId = 0;
00359
checkCursor();
00360
if (
startVal != null) bc.
seek(
startVal);
00361
else bc.
beforeFirst();
00362 }
catch (IOException e) {
00363
throw DbException.wrapThrowable(e);
00364 }
00365 }
00366
00367
00368
00369
00370 public void afterLast() throws SQLException {
00371
try {
00372 rowValid =
false;
00373 rowId = 0;
00374
checkCursor();
00375
if (
stopVal != null) bc.
seek(
stopVal);
00376
else bc.
afterLast();
00377 }
catch (IOException e) {
00378
throw DbException.wrapThrowable(e);
00379 }
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 public boolean isWritable(
int col) {
00393
return true;
00394 }
00395
00396
00397
00398
00399
00400 public Table getTable() {
return table; }
00401
00402
00403 public String
toString() {
00404
try {
00405 StringBuffer sb =
00406
new StringBuffer(
Table.strip(getClass().
getName()));
00407 sb.append(
": ");
00408 sb.append(
constraint.
getName());
00409
if (outer != null) {
00410 sb.append(
" (outer ");
00411 sb.append(outer.toString());
00412 sb.append(
")");
00413 }
00414 sb.append(
" {");
00415
for (
int i = 1; i <=
getColumnCount(); i++) {
00416
Column c = getColumn(i);
00417
if (i > 1) sb.append(
',');
00418 sb.append(c.
getName());
00419 }
00420 sb.append(
'}');
00421
return sb.toString();
00422 }
catch (Exception e) {
00423
Debug.print(e);
00424
return this.getClass().getName();
00425 }
00426 }
00427
00428 }