1 23 24 30 31 package com.sun.jdo.spi.persistence.support.sqlstore.sql.generator; 32 33 import org.netbeans.modules.dbschema.ColumnElement; 34 35 import com.sun.jdo.api.persistence.support.JDOFatalDataStoreException; 36 import com.sun.jdo.api.persistence.support.JDOFatalInternalException; 37 import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc; 38 import com.sun.jdo.spi.persistence.support.sqlstore.ValueFetcher; 39 import com.sun.jdo.spi.persistence.support.sqlstore.database.DBVendorType; 40 import com.sun.jdo.spi.persistence.support.sqlstore.model.TableDesc; 41 import com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl; 42 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintField; 43 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintFieldDesc; 44 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintNode; 45 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintOperation; 46 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintJoin; 47 import com.sun.jdo.spi.persistence.utility.I18NHelper; 48 49 import java.util.ArrayList ; 50 import java.util.List ; 51 import java.sql.SQLException ; 52 53 54 57 public class SelectStatement extends Statement { 58 59 60 private boolean isJoined; 61 62 private StringBuffer orderClause = new StringBuffer (); 63 64 65 SelectQueryPlan plan; 66 67 public SelectStatement(DBVendorType vendorType, SelectQueryPlan plan) { 68 super(vendorType); 69 this.plan = plan; 70 constraint = plan.getConstraint(); 71 } 72 73 public boolean isJoined() { 74 return isJoined; 75 } 76 77 public void markJoined() { 78 isJoined = true; 79 } 80 81 public ColumnRef addColumn(ColumnElement columnElement, 82 QueryTable queryTable) { 83 84 ColumnRef columnRef = null; 85 86 if ((columnRef = getColumnRef(columnElement)) == null) { 87 columnRef = new ColumnRef(columnElement, queryTable); 88 addColumnRef(columnRef); 89 } 90 91 return columnRef; 92 } 93 94 public void copyColumns(SelectStatement sourceStatement) { 95 ArrayList columnRefs = sourceStatement.getColumnRefs(); 96 97 int index = columns.size() + 1; 98 99 for (int i = 0; i < columnRefs.size(); i++) { 100 ColumnRef cref = (ColumnRef) columnRefs.get(i); 102 cref.setIndex(index + i); 103 columns.add(cref); 104 } 105 } 106 107 protected boolean isUpdateLockRequired(QueryTable table) { 108 return (plan.options & RetrieveDescImpl.OPT_AGGREGATE) == 0 109 && table.getTableDesc().isUpdateLockRequired(); 110 } 111 112 public void appendTableText(StringBuffer text, QueryTable table) { 113 super.appendTableText(text, table); 114 115 if (isUpdateLockRequired(table)) { 116 text.append(vendorType.getHoldlock() ); 118 119 } 123 } 124 125 137 public boolean isColumnTypeDefinitionNeeded() { 138 return (plan.options & RetrieveDescImpl.OPT_COUNT_PC ) == 0; 139 } 140 141 142 public QueryPlan getQueryPlan() { 143 return plan; 144 } 145 146 149 protected void generateStatementText() { 150 StringBuffer constraints = processConstraints(); 154 StringBuffer outerJoinText = processOuterJoinConstraints(); 155 156 if (outerJoinText != null && outerJoinText.length() > 0) { 157 if (constraints.length() > 0 ) { 158 constraints.append(" and "); 159 } 160 constraints.append(outerJoinText); 161 } 162 163 StringBuffer whereClause = new StringBuffer (); 164 165 if (constraints.length() > 0 ) { 166 whereClause.append(" where ").append(constraints); 167 } 168 169 if ((plan.options & RetrieveDescImpl.OPT_COUNT_PC) == 0) { 170 generateRegularStatementText(whereClause); 171 } else { 172 generateCountStatementText(whereClause); 173 } 174 } 175 176 184 private void generateRegularStatementText(StringBuffer whereClause) { 185 186 statementText = new StringBuffer (); 187 188 StringBuffer columnText = generateColumnText(); 189 String tableListText = generateTableListText(); 190 String aggregateText = getAggregateText(); 191 String aggregateEnd = (aggregateText.length() > 0) ? ")" : ""; 193 if (orderClause.length() > 0) { 194 orderClause.insert(0, " order by "); 195 } 196 197 final boolean updateLockRequired = isUpdateLockRequired(); 198 StringBuffer forUpdateClause = generateForUpdateClause(updateLockRequired); 199 String distinctText = getDistinctText(updateLockRequired); 200 201 statementText.append("select "). append(aggregateText).append(distinctText).append(columnText).append(aggregateEnd). 204 append(" from ").append(tableListText). append(whereClause).append(orderClause).append(forUpdateClause); 206 } 207 208 220 private void generateCountStatementText(StringBuffer whereClause) { 221 222 final int selectedColumns = columns.size(); 223 224 if (selectedColumns == 1) { 225 generateRegularStatementText(whereClause); 227 } else { 228 boolean oneTable = tableList.size() == 1; 229 230 if ((plan.options & RetrieveDescImpl.OPT_DISTINCT) == 0 231 || oneTable) { 232 for (int i = selectedColumns; i > 1; ) { columns.remove(--i); } 236 if (oneTable) { 237 plan.options &= ~RetrieveDescImpl.OPT_DISTINCT; 240 } 241 generateRegularStatementText(whereClause); 243 } else { 244 generateCorrelatedExistsText(whereClause); 248 249 columns.clear(); 253 } 254 } 255 } 256 257 265 private void generateCorrelatedExistsText(StringBuffer whereClause) { 266 267 statementText = new StringBuffer (); 268 269 273 boolean updateLockRequired = isUpdateLockRequired(); 275 StringBuffer forUpdateClause = generateForUpdateClause(updateLockRequired); 276 277 StringBuffer primaryTableText = new StringBuffer (); 278 QueryTable primaryTable = generatePrimaryTableText(primaryTableText); 279 280 tableList.remove(primaryTable); 286 String tableListText = generateTableListText(); 287 288 statementText.append("select count(*) from "). append(primaryTableText). 291 append(" where exists (select * from "). append(tableListText).append(whereClause).append(")"). append(forUpdateClause); 294 } 295 296 302 private QueryTable generatePrimaryTableText(StringBuffer primaryTableText) { 303 QueryTable primaryTable = ((ColumnRef)columns.get(0)).getQueryTable(); 306 307 appendTableText(primaryTableText, primaryTable); 309 310 return primaryTable; 311 } 312 313 protected StringBuffer generateColumnText() { 314 StringBuffer columnText = new StringBuffer (); 315 316 for (int i = 0; i < columns.size(); i++) { 317 ColumnRef cr = (ColumnRef) columns.get(i); 318 319 columnText.append("t").append(cr.getQueryTable().getTableIndex()).append("."); appendQuotedText(columnText, cr.getName()); 321 columnText.append(", "); } 323 columnText.delete(columnText.length() - 2, columnText.length()); 324 return columnText; 325 } 326 327 private String getAggregateText() { 328 int aggregateOption = plan.options & RetrieveDescImpl.OPT_AGGREGATE; 329 330 switch (aggregateOption) { 331 case RetrieveDescImpl.OPT_AVG: 332 return "AVG( "; case RetrieveDescImpl.OPT_MIN: 334 return "MIN("; case RetrieveDescImpl.OPT_MAX: 336 return "MAX("; case RetrieveDescImpl.OPT_SUM: 338 return "SUM("; case RetrieveDescImpl.OPT_COUNT: 340 case RetrieveDescImpl.OPT_COUNT_PC: 341 return "COUNT("; default: 343 return ""; } 345 } 346 347 private StringBuffer generateForUpdateClause(boolean updateLockRequired) { 348 StringBuffer forUpdateClause = new StringBuffer (); 349 350 if (updateLockRequired) { 351 if (!vendorType.isUpdateLockSupported() ) { 353 throw new JDOFatalDataStoreException(I18NHelper.getMessage(messages, 356 "sqlstore.selectstatement.noupdatelocksupport")); } 358 359 String vendorForUpdate = vendorType.getForUpdate().trim(); 361 boolean vendorHasForUpdateClause = (vendorForUpdate.length() != 0); 362 363 if (vendorHasForUpdateClause) { 364 forUpdateClause.append(" ").append(vendorForUpdate).append(" "); 365 366 if (vendorType.isLockColumnListSupported()) { 367 for (int i = 0; i < tableList.size(); i++) { 368 QueryTable queryTable = (QueryTable) tableList.get(i); 369 if (isUpdateLockRequired(queryTable)) { 370 TableDesc tableDesc = queryTable.getTableDesc(); 371 ColumnElement ce = (ColumnElement) tableDesc.getKey().getColumns().get(0); 373 forUpdateClause.append("t").append(i).append("."); appendQuotedText(forUpdateClause, ce.getName().getName()); 375 forUpdateClause.append(", "); } 377 } 378 forUpdateClause.delete(forUpdateClause.length() - 2, forUpdateClause.length()); 380 } 381 } 382 } 383 384 return forUpdateClause; 385 } 386 387 private String getDistinctText(boolean updateLockRequired) { 388 String distinctText = ""; 390 if ((plan.options & RetrieveDescImpl.OPT_DISTINCT) > 0) { 391 if( !updateLockRequired || vendorType.isDistinctSupportedWithUpdateLock()) { 392 396 distinctText = "distinct "; } 401 } 402 return distinctText; 403 } 404 405 411 private boolean isUpdateLockRequired() { 412 boolean updateLockRequired = false; 413 414 for (int i = 0; i < tableList.size() && !updateLockRequired; i++) { 416 QueryTable queryTable = (QueryTable) tableList.get(i); 417 updateLockRequired = isUpdateLockRequired(queryTable); 418 } 419 420 return updateLockRequired; 421 } 422 423 427 protected void processRootConstraint(ConstraintOperation opNode, 428 List stack, 429 StringBuffer whereText) { 430 int op = opNode.operation; 431 int opInfo = operationFormat(op); 432 433 if ((opInfo & OP_ORDERBY_MASK) > 0) { 434 stack.remove(stack.size() - 1); 435 ConstraintNode node = (ConstraintNode) stack.get(stack.size() - 1); 436 437 if (!(node instanceof ConstraintField)) { 438 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 439 "core.constraint.needfieldnode")); } else { 441 processOrderByField((ConstraintFieldDesc) node, op); 442 stack.remove(stack.size() - 1); 443 } 444 } else { 445 super.processRootConstraint(opNode, stack, whereText); 446 } 447 } 448 449 protected void processIrregularOperation(ConstraintOperation opNode, 450 int opCode, 451 List stack, 452 StringBuffer result) { 453 switch (opCode) { 454 case ActionDesc.OP_EQUIJOIN: 455 processJoinOperation((ConstraintJoin)opNode, result); 456 break; 457 default: 458 super.processIrregularOperation(opNode, opCode, stack, result); 459 } 460 } 461 462 469 private StringBuffer processOuterJoinConstraints() { 470 StringBuffer joinCondition = null; 471 final List joinStack = constraint.getOuterJoinConstraints(); 472 final int joinStackSize = joinStack.size(); 473 474 if (joinStackSize > 0) { 475 joinCondition = new StringBuffer (); 476 for (int i = 0; i < joinStackSize; i++) { 477 ConstraintJoin joinNode = (ConstraintJoin) joinStack.get(i); 478 processJoinOperation(joinNode, joinCondition); 479 } 480 } 481 return joinCondition; 482 } 483 484 493 private void processJoinOperation(ConstraintJoin jnode, 494 StringBuffer whereText) { 495 int opCode = jnode.operation; 496 boolean doAnsiJoin = opCode != ActionDesc.OP_EQUIJOIN 499 && !vendorType.isNativeOuterJoin(); 500 501 if (doAnsiJoin) { 502 generateAnsiJoin(jnode, opCode); 503 } else { 504 generateJoin(jnode, whereText, opCode); 505 } 506 } 507 508 521 private void generateJoin(ConstraintJoin jnode, 522 StringBuffer whereText, 523 int opCode) { 524 525 for (int i = 0; i < jnode.fromColumns.size(); i++) { 526 ColumnElement fromColumn = (ColumnElement)jnode.fromColumns.get(i); 527 ColumnElement toColumn = (ColumnElement)jnode.toColumns.get(i); 528 QueryTable fromTable = findQueryTable(jnode.fromPlan, fromColumn); 529 QueryTable toTable = findQueryTable(jnode.toPlan, toColumn); 530 531 addQueryTable(fromTable); 532 addQueryTable(toTable); 533 toTable.prevTable = null; 534 535 appendJoinCondition(whereText, 536 fromTable, toTable, fromColumn, toColumn, 537 getJoinOperator(opCode)); 538 539 if (opCode == ActionDesc.OP_LEFTJOIN ) { 540 whereText.append(vendorType.getLeftJoinPost()); 542 } 543 } 544 } 545 546 557 private void generateAnsiJoin(ConstraintJoin jnode, int opCode) { 558 559 for (int i = 0; i < jnode.fromColumns.size(); i++) { 560 ColumnElement fromColumn = (ColumnElement)jnode.fromColumns.get(i); 561 ColumnElement toColumn = (ColumnElement)jnode.toColumns.get(i); 562 QueryTable fromTable = findQueryTable(jnode.fromPlan, fromColumn); 563 QueryTable toTable = findQueryTable(jnode.toPlan, toColumn); 564 565 processFromClause(fromTable, toTable); 567 568 if (toTable.onClause == null) { 570 toTable.onClause = new StringBuffer (); 571 } 572 573 appendJoinCondition(toTable.onClause, fromTable, toTable, fromColumn, toColumn, "="); 575 fromTable.joinOp = opCode; 576 } 577 } 578 579 589 private static void processFromClause(QueryTable fromTable, QueryTable toTable) { 590 591 if (toTable.prevTable != null && toTable.prevTable != fromTable) { 592 } 594 595 602 if (fromTable.nextTable == null) { 603 fromTable.nextTable = new ArrayList (); 604 fromTable.nextTable.add(toTable); 605 toTable.prevTable = fromTable; 606 } else { 607 if (!fromTable.nextTable.contains(toTable)) { 609 fromTable.nextTable.add(toTable); 610 toTable.prevTable = fromTable; 611 } 612 } 613 } 614 615 627 private void appendJoinCondition(StringBuffer result, 628 QueryTable fromTable, QueryTable toTable, 629 ColumnElement fromColumn, ColumnElement toColumn, 630 String joinOp) { 631 if (result.length() > 0) { 632 result.append(" and "); 634 } 635 636 result.append("t").append(fromTable.getTableIndex()).append("."); appendQuotedText(result, fromColumn.getName().getName()); 638 result.append(" ").append(joinOp). append(" t").append(toTable.getTableIndex()).append("."); appendQuotedText(result, toColumn.getName().getName()); 641 } 642 643 650 protected String getJoinOperator(int operation) { 651 String result = null; 652 653 switch (operation) { 654 case ActionDesc.OP_EQUIJOIN: 655 result = " = "; break; 657 case ActionDesc.OP_LEFTJOIN: 658 result = vendorType.getLeftJoin(); 659 break; 660 case ActionDesc.OP_RIGHTJOIN: 661 result = vendorType.getRightJoin(); 662 break; 663 default: 664 throw new JDOFatalInternalException( 665 I18NHelper.getMessage(messages, 666 "core.constraint.illegalop", operation)); } 668 return result; 669 } 670 671 private static QueryTable findQueryTable(QueryPlan plan, ColumnElement ce) { 672 QueryTable table = plan.findQueryTable(ce.getDeclaringTable()); 673 674 if (table == null) { 675 } 677 678 return table; 679 } 680 681 private String generateTableListText() { 682 StringBuffer str = new StringBuffer (); 683 684 for (int i = 0; i < tableList.size(); i++) { 685 QueryTable t = (QueryTable) tableList.get(i); 686 687 if (t.prevTable == null && t.nextTable == null) { 688 appendTableText(str, t); 689 str.append(", "); } else { 691 693 if (t.prevTable == null) { 694 696 appendAnsiJoinText(str, t); 697 } else { 698 700 while (t.prevTable != null) { 701 t = t.prevTable; 702 } 703 704 if (!tableList.contains(t)) { 705 709 appendAnsiJoinText(str, t); 710 } 711 } 712 } 713 } 714 715 str.delete(str.length() - 2, str.length()); 716 717 return str.toString(); 718 } 719 720 private void appendAnsiJoinText(StringBuffer str, QueryTable t) { 721 str.append(vendorType.getTableListStart()); 724 appendAnsiJoinTableText(str, t); 725 str.append(vendorType.getTableListEnd()); 726 str.append(", "); } 728 729 737 private void appendAnsiJoinTableText(StringBuffer text, QueryTable table) { 738 739 if (table.joinOp == ActionDesc.OP_RIGHTJOIN) { 740 text.append(vendorType.getRightJoinPre()); 741 } 742 743 if (table.prevTable == null) { 744 appendTableText(text, table); 745 } 746 747 for (int i = 0; i < table.nextTable.size(); i++) { 748 QueryTable toTable = (QueryTable) table.nextTable.get(i); 749 text.append(getJoinOperator(table.joinOp)).append(" "); 751 appendTableText(text, toTable); 752 753 if (toTable.onClause != null) { 754 text.append(" on "); text.append(toTable.onClause); 756 } 757 758 if (toTable.nextTable != null) { 759 appendAnsiJoinTableText(text, toTable); 760 } 761 762 if (table.joinOp == ActionDesc.OP_LEFTJOIN) { 766 text.append(vendorType.getLeftJoinPost()); 767 } 768 } 769 } 770 771 778 private void processOrderByField(ConstraintFieldDesc fieldNode, int op) { 779 QueryPlan thePlan = getOriginalPlan(fieldNode); 780 StringBuffer orderText = new StringBuffer (); 781 782 generateColumnText(fieldNode.desc, thePlan, orderText); 783 784 if (op == ActionDesc.OP_ORDERBY_DESC) { 785 orderText.append(" desc"); } 787 788 if (orderClause.length() > 0) { 789 orderText.append(", "); orderText.append(orderClause); 791 } 792 orderClause = orderText; 793 } 794 795 803 public void bindInputValues(DBStatement s, ValueFetcher parameters) 804 throws SQLException { 805 for (int i = 0, size = inputDesc.values.size(); i < size; i++) { 806 InputValue inputVal = (InputValue) inputDesc.values.get(i); 807 s.bindInputColumn(i + 1, getInputValue(inputVal, parameters), 808 inputVal.getColumnElement(), vendorType); 809 } 810 } 811 812 818 private Object [] getInputValues(ValueFetcher parameters) { 819 final int size = inputDesc.values.size(); 820 Object [] inputValues = new Object [size]; 821 for (int i = 0; i < size; i++) { 822 InputValue inputValue = (InputValue) inputDesc.values.get(i); 823 inputValues[i] = getInputValue(inputValue, parameters); 824 } 825 return inputValues; 826 } 827 828 834 public String getFormattedSQLText(ValueFetcher parameters) { 835 return formatSqlText(getText(), getInputValues(parameters)) ; 836 } 837 838 848 private static Object getInputValue(InputValue inputVal, 849 ValueFetcher parameters) { 850 Object val; 851 if (inputVal instanceof InputParamValue) { 852 int paramIndex = ((InputParamValue) inputVal).getParamIndex().intValue(); 853 val = parameters.getValue(paramIndex); 854 } 855 else { 856 val = inputVal.getValue(); 857 } 858 return val; 859 } 860 861 } 862 | Popular Tags |