1 package com.quadcap.sql; 2 3 40 41 import java.io.Externalizable ; 42 import java.io.IOException ; 43 import java.io.ObjectInput ; 44 import java.io.ObjectOutput ; 45 46 import java.util.Vector ; 47 48 import java.sql.SQLException ; 49 50 import com.quadcap.sql.types.Op; 51 import com.quadcap.sql.types.Value; 52 import com.quadcap.sql.types.ValueLong; 53 import com.quadcap.sql.types.ValueNull; 54 55 import com.quadcap.util.Debug; 56 57 62 63 public class SelectExpression extends TableExpression 64 implements Externalizable 65 { 66 boolean distinct = false; 67 Vector items = null; 68 Vector from = null; 69 Vector groupBy = null; 70 Expression having = null; 71 Vector aggregates = null; 72 73 76 public SelectExpression() {} 77 78 81 public SelectExpression(String tableName, Expression where) { 82 Vector v = new Vector (); 83 v.addElement(new SelectFromTable(tableName)); 84 this.setFrom(v); 85 this.setWhere(where); 86 } 87 88 91 public Vector getFrom() { 92 return from; 93 } 94 95 98 public void setDistinct(boolean b) { this.distinct = b; } 99 100 103 public void setItems(Vector v) { this.items = v; } 104 105 108 public void setFrom(Vector v) { this.from = v; } 109 110 113 public void setGroupBy(Vector v) { this.groupBy = v; } 114 115 118 public void setHaving(Expression e) { this.having = e; } 119 120 123 public int rank() { return 2; } 124 125 129 public boolean isUpdatable() { 130 if (groupBy != null) return false; 131 if (having != null) return false; 132 if (distinct) return false; 133 if (from == null || from.size() > 1) return false; 134 if (aggregates != null && aggregates.size() > 0) return false; 135 136 TableExpression t = (TableExpression)from.elementAt(0); 137 if (!t.isUpdatable()) return false; 138 139 return true; } 141 142 151 TableExpression scheduleJoin() throws SQLException { 152 while (from.size() > 1) { 153 TableExpression a = (TableExpression)from.elementAt(0); 154 TableExpression b = (TableExpression)from.elementAt(1); 155 JoinedTable t = new JoinedTable(Op.CROSS, a, b); 156 from.removeElementAt(0); 158 from.setElementAt(t, 0); 159 } 160 TableExpression item = (TableExpression)from.elementAt(0); 161 return item; 162 } 163 164 170 public Cursor getCursor(Session session, Cursor cur) throws SQLException { 171 if (from == null) { 172 Row row = new Row(items.size()); 173 TupleImpl t = new TupleImpl(); 174 for (int i = 0; i < items.size(); i++) { 175 SelectItem item = (SelectItem)items.elementAt(i); 176 Expression expr = item.getExpression(); 177 Value v = expr.getValue(session, cur); 178 String name = item.getAsName(); 179 if (name == null) name = "Column" + i; 180 t.addColumn(name, v.getType()); 181 row.set(i+1, expr.getValue(session, cur)); 182 } 183 return new StaticCursor(session, t, row); 184 } 185 TableExpression tab = null; 186 187 if (from.size() > 1) { 188 tab = scheduleJoin(); 189 } else { 190 tab = (TableExpression)from.elementAt(0); 191 } 192 193 tab.setWhere(where); 195 196 Cursor c = tab.getCursor(session, cur); 197 if (where != null) { 198 c = new PredicateCursor(session, c, where); 202 } 203 if (groupBy != null) { 204 GroupByCursor gc = new GroupByCursor(session, c, groupBy); 205 c = gc; 206 Vector tItems = items; if (having != null) { 208 int cnt = (items == null) ? 0 : items.size(); 209 tItems = new Vector (cnt + 1); 210 for (int i = 0; i < cnt; i++) { 211 tItems.addElement(items.elementAt(i)); 212 } 213 tItems.addElement(new SelectItem(having)); 214 } 215 if (isAggregate(session, tItems)) { 216 ItemsCursor ic = new ItemsCursor(session, gc, tItems); 217 c = new AggregateCursor(session, ic, gc, aggregates); 218 if (having != null) { 219 c = new HavingCursor(session, c); 220 } 221 } else if (tItems != null) { 222 ItemsCursor ic = new ItemsCursor(session, gc, tItems); 223 c = ic; 224 c = new AggregateCursor(session, ic, gc, aggregates); 225 if (having != null) { 226 c = new HavingCursor(session, c); 227 } 228 } 229 } else { 230 if (isAggregate(session, items)) { 231 Cursor optimized = optimizeAggregate(session, c, items); 232 if (optimized != null) { 233 c = optimized; 234 } else { 235 ItemsCursor ic = new ItemsCursor(session, c, items); 236 c = new AggregateCursor(session, ic, null, aggregates); 237 } 238 } else { 239 if (items != null) { 240 c = new ItemsCursor(session, c, items); 241 } 242 } 243 } 244 if (distinct) { 245 c = new DistinctCursor(session, c); 246 } 247 248 if (cur != null) c.setOuterCursor(cur); 249 showCursor(c); 251 return c; 253 } 254 255 258 class IsAggregate implements ExpressionVisitor { 259 Session session = null; 260 Vector aggregates = null; 261 boolean seenName = false; 262 boolean seenAggregate = false; 263 264 public IsAggregate(Session session) { 265 this.session = session; 266 } 267 268 public void visit(Expression sub) { 269 if (sub instanceof AggregateExpression) { 270 seenAggregate = true; 271 if (aggregates == null) { 277 aggregates = new Vector (); 278 } 279 aggregates.addElement(sub); 280 } else { 281 seenName |= (sub instanceof NameExpression); 282 sub.visitSubExpressions(this); 283 } 284 } 285 286 void reset() { 287 seenName = seenAggregate = false; 288 } 289 } 290 291 295 boolean isAggregate(Session session, Vector items) throws SQLException { 296 if (items == null) return false; 297 int cnt = 0; 298 IsAggregate isVis = new IsAggregate(session); 299 for (int i = 0; i < items.size(); i++) { 300 SelectItem item = (SelectItem)items.elementAt(i); 301 Expression expression = item.getExpression(); 302 isVis.reset(); 303 isVis.visit(expression); 304 if (isVis.seenAggregate && isVis.seenName && groupBy == null) { 305 throw new SQLException ("Expressions can't mix aggregate and " + 306 "non-aggregate values", "42000"); 307 } 308 if (isVis.seenAggregate) cnt++; 309 } 310 this.aggregates = isVis.aggregates; 311 if (cnt == 0) return false; 312 return true; 313 } 314 315 318 Cursor staticCursor(Session session, Cursor c, Vector items, Value v) 319 throws SQLException 320 { 321 Row r = new Row(1); 322 r.set(1, v); 323 ItemsCursor it = new ItemsCursor(session, c, items); 324 return new StaticCursor(session, it, r); 325 } 326 327 332 Cursor optimizeAggregate(Session session, Cursor c, Vector items) 333 throws SQLException 334 { 335 Cursor ret = null; 336 if (c instanceof IndexCursor) { 337 IndexCursor ic = (IndexCursor)c; 338 if (items.size() == 1) { 339 SelectItem item = (SelectItem)items.get(0); 340 Expression te = item.getExpression(); 341 if (te instanceof AggregateExpression) { 342 AggregateExpression ag = (AggregateExpression)te; 343 if (ag.isMin() || ag.isMax()) { 344 Expression inner = ag.getInnerExpression(); 345 if (inner instanceof NameExpression) { 346 NameExpression nam = (NameExpression)inner; 347 Column col = ic.getConstraint().getColumn(0); 348 if (nam.getName().equals(col.getName())) { 349 if (c.absolute(ag.isMax() ? -1 : 1)) { 352 Row r = c.getRow(); 353 ret = staticCursor(session, c, items, 354 r.item(1)); 355 c.close(); 356 } 357 } 358 } 359 } else if (ag.isCount() && ag.all && c.size() > 0) { 360 ret = staticCursor(session, c, items, 362 new ValueLong(c.size())); 363 c.close(); 364 } 365 } 366 } 367 } 368 return ret; 369 } 370 371 376 public Value getValue(Session session, Cursor cur) throws SQLException { 377 Value ret = ValueNull.valueNull; 378 Cursor cursor = getCursor(session, cur); 379 try { 380 if (cursor.next()) { 381 Row row = cursor.getRow(); 382 if (row.size() == 1) { 383 ret = row.item(1); 384 } 385 if (cursor.next()) { 386 throw new SQLException ("Cardinality violation", "21000"); 387 } 388 } 389 return ret; 390 } finally { 391 cursor.close(); 392 } 393 } 394 395 398 public void getBaseTables(Vector v) { 399 for (int i = 0; i < from.size(); i++) { 400 ((TableExpression)from.elementAt(i)).getBaseTables(v); 401 } 402 } 403 404 407 public void visitSubExpressions(ExpressionVisitor ev) { 408 if (where != null) ev.visit(where); 409 } 410 411 414 class AndWhere implements ExpressionVisitor { 415 Expression where; 416 AndWhere(Expression where) { this.where = where; } 417 public void visit(Expression sub) { 418 if (sub instanceof TableExpression) { 419 TableExpression te = (TableExpression)sub; 420 if (!te.anded) { 421 Expression oldW = te.getWhere(); 422 if (oldW != null) { 423 where = new BinaryExpression(Op.AND, where, oldW); 424 } 425 te.setWhere(where); 426 te.anded = true; 427 } 428 sub.visitSubExpressions(this); 429 } 430 } 431 } 432 433 438 public void invert() { 439 throw new RuntimeException ( 440 "invert not implemented for SelectExpression"); 441 } 442 443 446 public void readExternal(ObjectInput in) 447 throws IOException , ClassNotFoundException 448 { 449 this.distinct = (in.read() == 1); 450 this.items = (Vector )in.readObject(); 451 this.from = (Vector )in.readObject(); 452 this.where = (Expression)in.readObject(); 453 this.groupBy = (Vector )in.readObject(); 454 this.having = (Expression)in.readObject(); 455 } 456 457 460 public void writeExternal(ObjectOutput out) throws IOException { 461 out.write(distinct ? 1 : 0); 462 out.writeObject(items); 463 out.writeObject(from); 464 out.writeObject(where); 465 out.writeObject(groupBy); 466 out.writeObject(having); 467 } 468 469 472 public String toString() { 473 StringBuffer sb = new StringBuffer ("SELECT "); 474 if (items == null) { 475 sb.append("*"); 476 } else { 477 for (int i = 0; i < items.size(); i++) { 478 if (i > 0) sb.append(','); 479 sb.append(items.elementAt(i).toString()); 480 } 481 } 482 if (from != null) { 483 sb.append(" FROM "); 484 for (int i = 0; i < from.size(); i++) { 485 if (i > 0) sb.append(','); 486 sb.append(from.elementAt(i).toString()); 487 } 488 } 489 if (where != null) { 490 sb.append(" WHERE "); 491 sb.append(where.toString()); 492 } 493 if (groupBy != null) { 494 sb.append(" GROUP BY "); 495 for (int i = 0; i < groupBy.size(); i++) { 496 if (i > 0) sb.append(','); 497 sb.append(groupBy.elementAt(i).toString()); 498 } 499 } 500 if (having != null) { 501 sb.append(" HAVING "); 502 sb.append(having.toString()); 503 } 504 return sb.toString(); 505 } 506 507 511 public static final void showCursor(Cursor c) { 512 try { 513 if (Trace.bit(2)) { 514 Debug.println(c.toString()); 515 } 516 } catch (Exception e) { 517 Debug.print(e); 518 } 519 } 520 521 524 public static void showCursor(Cursor c, boolean really) { 525 try { 526 if (really) { 527 Debug.println("\n" + c); 528 } 529 } catch (Throwable e) { 530 Debug.print(e); 531 } 532 } 533 534 public String name() { 535 return toString(); 536 } 537 539 540 } 541 542 | Popular Tags |