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.Externalizable;
00042
import java.io.IOException;
00043
import java.io.ObjectInput;
00044
import java.io.ObjectOutput;
00045
00046
import java.util.Vector;
00047
00048
import java.sql.SQLException;
00049
00050
import com.quadcap.sql.types.Op;
00051
import com.quadcap.sql.types.Value;
00052
import com.quadcap.sql.types.ValueLong;
00053
import com.quadcap.sql.types.ValueNull;
00054
00055
import com.quadcap.util.Debug;
00056
00057
00058
00059
00060
00061
00062
00063 public class SelectExpression extends TableExpression
00064 implements
Externalizable
00065 {
00066 boolean distinct =
false;
00067 Vector
items = null;
00068 Vector
from = null;
00069 Vector
groupBy = null;
00070 Expression having = null;
00071 Vector
aggregates = null;
00072
00073
00074
00075
00076 public SelectExpression() {}
00077
00078
00079
00080
00081 public SelectExpression(String tableName,
Expression where) {
00082 Vector v =
new Vector();
00083 v.addElement(
new SelectFromTable(tableName));
00084
this.setFrom(v);
00085
this.setWhere(where);
00086 }
00087
00088
00089
00090
00091 public Vector
getFrom() {
00092
return from;
00093 }
00094
00095
00096
00097
00098 public void setDistinct(
boolean b) {
this.distinct = b; }
00099
00100
00101
00102
00103 public void setItems(Vector v) {
this.items = v; }
00104
00105
00106
00107
00108 public void setFrom(Vector v) {
this.from = v; }
00109
00110
00111
00112
00113 public void setGroupBy(Vector v) {
this.groupBy = v; }
00114
00115
00116
00117
00118 public void setHaving(
Expression e) {
this.having = e; }
00119
00120
00121
00122
00123 public int rank() {
return 2; }
00124
00125
00126
00127
00128
00129 public boolean isUpdatable() {
00130
if (
groupBy != null)
return false;
00131
if (
having != null)
return false;
00132
if (
distinct)
return false;
00133
if (
from == null ||
from.size() > 1)
return false;
00134
if (
aggregates != null &&
aggregates.size() > 0)
return false;
00135
00136
TableExpression t = (
TableExpression)
from.elementAt(0);
00137
if (!t.
isUpdatable())
return false;
00138
00139
return true;
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 TableExpression scheduleJoin() throws SQLException {
00152
while (
from.size() > 1) {
00153
TableExpression a = (
TableExpression)
from.elementAt(0);
00154
TableExpression b = (
TableExpression)
from.elementAt(1);
00155
JoinedTable t =
new JoinedTable(
Op.CROSS, a, b);
00156
00157
from.removeElementAt(0);
00158
from.setElementAt(t, 0);
00159 }
00160
TableExpression item = (
TableExpression)
from.elementAt(0);
00161
return item;
00162 }
00163
00164
00165
00166
00167
00168
00169
00170 public Cursor getCursor(
Session session,
Cursor cur)
throws SQLException {
00171
if (
from == null) {
00172
Row row =
new Row(
items.size());
00173
TupleImpl t =
new TupleImpl();
00174
for (
int i = 0; i <
items.size(); i++) {
00175
SelectItem item = (
SelectItem)
items.elementAt(i);
00176
Expression expr = item.
getExpression();
00177
Value v = expr.
getValue(session, cur);
00178 String
name = item.
getAsName();
00179
if (name == null) name =
"Column" + i;
00180 t.
addColumn(name, v.
getType());
00181 row.
set(i+1, expr.
getValue(session, cur));
00182 }
00183
return new StaticCursor(session, t, row);
00184 }
00185
TableExpression tab = null;
00186
00187
if (
from.size() > 1) {
00188 tab =
scheduleJoin();
00189 }
else {
00190 tab = (
TableExpression)
from.elementAt(0);
00191 }
00192
00193
00194 tab.
setWhere(where);
00195
00196
Cursor c = tab.
getCursor(session, cur);
00197
if (where != null) {
00198
00199
00200
00201 c =
new PredicateCursor(session, c, where);
00202 }
00203
if (
groupBy != null) {
00204
GroupByCursor gc =
new GroupByCursor(session, c,
groupBy);
00205 c = gc;
00206 Vector tItems =
items;
00207
if (
having != null) {
00208
int cnt = (items == null) ? 0 : items.size();
00209 tItems =
new Vector(cnt + 1);
00210
for (
int i = 0; i < cnt; i++) {
00211 tItems.addElement(items.elementAt(i));
00212 }
00213 tItems.addElement(
new SelectItem(
having));
00214 }
00215
if (
isAggregate(session, tItems)) {
00216
ItemsCursor ic =
new ItemsCursor(session, gc, tItems);
00217 c =
new AggregateCursor(session, ic, gc,
aggregates);
00218
if (
having != null) {
00219 c =
new HavingCursor(session, c);
00220 }
00221 }
else if (tItems != null) {
00222
ItemsCursor ic =
new ItemsCursor(session, gc, tItems);
00223 c = ic;
00224 c =
new AggregateCursor(session, ic, gc,
aggregates);
00225
if (
having != null) {
00226 c =
new HavingCursor(session, c);
00227 }
00228 }
00229 }
else {
00230
if (
isAggregate(session,
items)) {
00231
Cursor optimized =
optimizeAggregate(session, c,
items);
00232
if (optimized != null) {
00233 c = optimized;
00234 }
else {
00235
ItemsCursor ic =
new ItemsCursor(session, c,
items);
00236 c =
new AggregateCursor(session, ic, null,
aggregates);
00237 }
00238 }
else {
00239
if (
items != null) {
00240 c =
new ItemsCursor(session, c,
items);
00241 }
00242 }
00243 }
00244
if (
distinct) {
00245 c =
new DistinctCursor(session, c);
00246 }
00247
00248
if (cur != null) c.
setOuterCursor(cur);
00249
00250
showCursor(c);
00251
00252
return c;
00253 }
00254
00255
00256
00257
00258 class IsAggregate implements ExpressionVisitor {
00259 Session session = null;
00260 Vector
aggregates = null;
00261 boolean seenName =
false;
00262 boolean seenAggregate =
false;
00263
00264 public IsAggregate(
Session session) {
00265
this.session = session;
00266 }
00267
00268 public void visit(
Expression sub) {
00269
if (sub instanceof
AggregateExpression) {
00270
seenAggregate =
true;
00271
00272
00273
00274
00275
00276
if (
aggregates == null) {
00277
aggregates =
new Vector();
00278 }
00279
aggregates.addElement(sub);
00280 }
else {
00281
seenName |= (sub instanceof
NameExpression);
00282 sub.
visitSubExpressions(
this);
00283 }
00284 }
00285
00286 void reset() {
00287
seenName =
seenAggregate =
false;
00288 }
00289 }
00290
00291
00292
00293
00294
00295 boolean isAggregate(
Session session, Vector items)
throws SQLException {
00296
if (
items == null)
return false;
00297
int cnt = 0;
00298
IsAggregate isVis =
new IsAggregate(session);
00299
for (
int i = 0; i <
items.size(); i++) {
00300
SelectItem item = (
SelectItem)
items.elementAt(i);
00301
Expression expression = item.
getExpression();
00302 isVis.
reset();
00303 isVis.
visit(expression);
00304
if (isVis.
seenAggregate && isVis.
seenName &&
groupBy == null) {
00305
throw new SQLException(
"Expressions can't mix aggregate and " +
00306
"non-aggregate values",
"42000");
00307 }
00308
if (isVis.
seenAggregate) cnt++;
00309 }
00310
this.aggregates = isVis.
aggregates;
00311
if (cnt == 0)
return false;
00312
return true;
00313 }
00314
00315
00316
00317
00318 Cursor staticCursor(
Session session,
Cursor c, Vector items,
Value v)
00319
throws SQLException
00320 {
00321
Row r =
new Row(1);
00322 r.
set(1, v);
00323
ItemsCursor it =
new ItemsCursor(session, c,
items);
00324
return new StaticCursor(session, it, r);
00325 }
00326
00327
00328
00329
00330
00331
00332 Cursor optimizeAggregate(
Session session,
Cursor c, Vector items)
00333
throws SQLException
00334 {
00335
Cursor ret = null;
00336
if (c instanceof
IndexCursor) {
00337
IndexCursor ic = (
IndexCursor)c;
00338
if (
items.size() == 1) {
00339
SelectItem item = (
SelectItem)
items.get(0);
00340
Expression te = item.
getExpression();
00341
if (te instanceof
AggregateExpression) {
00342
AggregateExpression ag = (
AggregateExpression)te;
00343
if (ag.
isMin() || ag.
isMax()) {
00344
Expression inner = ag.
getInnerExpression();
00345
if (inner instanceof
NameExpression) {
00346
NameExpression nam = (
NameExpression)inner;
00347
Column col = ic.
getConstraint().
getColumn(0);
00348
if (nam.
getName().equals(col.
getName())) {
00349
00350
00351
if (c.absolute(ag.
isMax() ? -1 : 1)) {
00352
Row r = c.getRow();
00353 ret = staticCursor(session, c,
items,
00354 r.
item(1));
00355 c.
close();
00356 }
00357 }
00358 }
00359 }
else if (ag.
isCount() && ag.
all && c.size() > 0) {
00360
00361 ret = staticCursor(session, c,
items,
00362
new ValueLong(c.size()));
00363 c.
close();
00364 }
00365 }
00366 }
00367 }
00368
return ret;
00369 }
00370
00371
00372
00373
00374
00375
00376 public Value getValue(
Session session,
Cursor cur)
throws SQLException {
00377
Value ret =
ValueNull.valueNull;
00378
Cursor cursor = getCursor(session, cur);
00379
try {
00380
if (cursor.
next()) {
00381
Row row = cursor.
getRow();
00382
if (row.
size() == 1) {
00383 ret = row.
item(1);
00384 }
00385
if (cursor.
next()) {
00386
throw new SQLException(
"Cardinality violation",
"21000");
00387 }
00388 }
00389
return ret;
00390 } finally {
00391 cursor.
close();
00392 }
00393 }
00394
00395
00396
00397
00398 public void getBaseTables(Vector v) {
00399
for (
int i = 0; i <
from.size(); i++) {
00400 ((
TableExpression)
from.elementAt(i)).getBaseTables(v);
00401 }
00402 }
00403
00404
00405
00406
00407 public void visitSubExpressions(
ExpressionVisitor ev) {
00408
if (where != null) ev.
visit(where);
00409 }
00410
00411
00412
00413
00414 class AndWhere implements ExpressionVisitor {
00415 Expression where;
00416 AndWhere(
Expression where) {
this.where = where; }
00417 public void visit(
Expression sub) {
00418
if (sub instanceof
TableExpression) {
00419
TableExpression te = (
TableExpression)sub;
00420
if (!te.
anded) {
00421
Expression oldW = te.
getWhere();
00422
if (oldW != null) {
00423
where =
new BinaryExpression(
Op.AND,
where, oldW);
00424 }
00425 te.
setWhere(
where);
00426 te.
anded =
true;
00427 }
00428 sub.
visitSubExpressions(
this);
00429 }
00430 }
00431 }
00432
00433
00434
00435
00436
00437
00438 public void invert() {
00439
throw new RuntimeException(
00440
"invert not implemented for SelectExpression");
00441 }
00442
00443
00444
00445
00446 public void readExternal(ObjectInput in)
00447
throws IOException, ClassNotFoundException
00448 {
00449
this.distinct = (in.read() == 1);
00450
this.items = (Vector)in.readObject();
00451
this.from = (Vector)in.readObject();
00452
this.where = (
Expression)in.readObject();
00453
this.groupBy = (Vector)in.readObject();
00454
this.having = (
Expression)in.readObject();
00455 }
00456
00457
00458
00459
00460 public void writeExternal(ObjectOutput out)
throws IOException {
00461 out.write(
distinct ? 1 : 0);
00462 out.writeObject(
items);
00463 out.writeObject(
from);
00464 out.writeObject(where);
00465 out.writeObject(
groupBy);
00466 out.writeObject(
having);
00467 }
00468
00469
00470
00471
00472 public String
toString() {
00473 StringBuffer sb =
new StringBuffer(
"SELECT ");
00474
if (
items == null) {
00475 sb.append(
"*");
00476 }
else {
00477
for (
int i = 0; i <
items.size(); i++) {
00478
if (i > 0) sb.append(
',');
00479 sb.append(
items.elementAt(i).toString());
00480 }
00481 }
00482
if (
from != null) {
00483 sb.append(
" FROM ");
00484
for (
int i = 0; i <
from.size(); i++) {
00485
if (i > 0) sb.append(
',');
00486 sb.append(
from.elementAt(i).toString());
00487 }
00488 }
00489
if (where != null) {
00490 sb.append(
" WHERE ");
00491 sb.append(where.
toString());
00492 }
00493
if (
groupBy != null) {
00494 sb.append(
" GROUP BY ");
00495
for (
int i = 0; i <
groupBy.size(); i++) {
00496
if (i > 0) sb.append(
',');
00497 sb.append(
groupBy.elementAt(i).toString());
00498 }
00499 }
00500
if (
having != null) {
00501 sb.append(
" HAVING ");
00502 sb.append(
having.
toString());
00503 }
00504
return sb.toString();
00505 }
00506
00507
00508
00509
00510
00511 public static final void showCursor(
Cursor c) {
00512
try {
00513
if (
Trace.bit(2)) {
00514
Debug.println(c.toString());
00515 }
00516 }
catch (Exception e) {
00517
Debug.print(e);
00518 }
00519 }
00520
00521
00522
00523
00524 public static void showCursor(
Cursor c,
boolean really) {
00525
try {
00526
if (really) {
00527
Debug.println(
"\n" + c);
00528 }
00529 }
catch (Throwable e) {
00530
Debug.print(e);
00531 }
00532 }
00533
00534 public String
name() {
00535
return toString();
00536 }
00537
00538
00539
00540 }
00541