1 23 24 30 31 package com.sun.jdo.spi.persistence.support.sqlstore.sql.generator; 32 33 import org.netbeans.modules.dbschema.ColumnElement; 34 import com.sun.jdo.api.persistence.support.JDOFatalInternalException; 35 import com.sun.jdo.api.persistence.support.JDOUserException; 36 import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc; 37 import com.sun.jdo.spi.persistence.support.sqlstore.LogHelperSQLStore; 38 import com.sun.jdo.spi.persistence.support.sqlstore.RetrieveDesc; 39 import com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager; 40 import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager; 41 import com.sun.jdo.spi.persistence.support.sqlstore.model.*; 42 import com.sun.jdo.spi.persistence.support.sqlstore.sql.ResultDesc; 43 import com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl; 44 import com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency; 45 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.*; 46 import com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration; 47 import com.sun.jdo.spi.persistence.utility.I18NHelper; 48 import com.sun.jdo.spi.persistence.utility.logging.Logger; 49 50 import java.util.*; 51 import java.sql.ResultSet ; 52 import java.sql.SQLException ; 53 54 55 60 public class SelectQueryPlan extends QueryPlan { 61 62 63 private static final int ST_JOINED = 0x2; 64 65 66 public static final int ST_C_BUILT = 0x4; 67 68 69 public static final int ST_OC_BUILT = 0x10; 70 71 76 protected Constraint constraint; 77 78 79 public int options; 80 81 82 private Iterator fieldIterator; 83 84 88 private int aggregateResultType; 89 90 94 private ArrayList foreignPlans; 95 96 100 protected ForeignFieldDesc parentField; 101 102 106 private boolean prefetched; 107 108 private Concurrency concurrency; 109 110 111 private BitSet hierarchicalGroupMask; 112 113 114 private BitSet independentGroupMask; 115 116 117 private BitSet fieldMask; 118 119 private Map foreignConstraintPlans; 120 121 private ResultDesc resultDesc; 122 123 128 private boolean appendAndOp; 130 131 132 private final static Logger logger = LogHelperSQLStore.getLogger(); 133 134 143 public static SelectQueryPlan newInstance(RetrieveDescImpl desc, 144 SQLStoreManager store, 145 Concurrency concurrency) { 146 SelectQueryPlan plan = null; 147 148 if ( (desc.getOptions() & RetrieveDescImpl.OPT_VERIFY) > 0) { 149 plan = new VerificationSelectPlan(desc, store); 150 } else { 151 plan = new SelectQueryPlan(desc, store, concurrency); 152 } 153 154 return plan; 155 } 156 157 167 public SelectQueryPlan(ActionDesc desc, 168 SQLStoreManager store, 169 Concurrency concurrency) { 170 171 super(desc, store); 172 action = ACT_SELECT; 173 174 fieldMask = new BitSet(); 176 hierarchicalGroupMask = new BitSet(); 177 independentGroupMask = new BitSet(); 178 this.concurrency = concurrency; 179 181 if (desc instanceof RetrieveDescImpl) { 182 RetrieveDescImpl retrieveDesc = (RetrieveDescImpl) desc; 183 retrieveDesc.setPlan(this); 184 185 constraint = retrieveDesc.getConstraint(); 187 options = retrieveDesc.getOptions(); 188 fieldIterator = retrieveDesc.getFields(); 189 aggregateResultType = retrieveDesc.getAggregateResultType(); 190 } else { 191 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 192 "core.generic.notinstanceof", desc.getClass().getName(), "RetrieveDescImpl")); } 194 } 195 196 public Constraint getConstraint() { 197 return constraint; 198 } 199 200 private void setFieldMask(int index) { 201 if (index < 0) { 202 index = config.fields.size() - index; 203 } 204 205 fieldMask.set(index); 206 } 207 208 private boolean getFieldMask(int index) { 209 if (index < 0) { 210 index = config.fields.size() - index; 211 } 212 213 return fieldMask.get(index); 214 } 215 216 222 protected void addTable(LocalFieldDesc fieldDesc) { 223 addColumn(fieldDesc, false, false); 224 } 225 226 233 protected void addColumn(LocalFieldDesc fieldDesc) { 234 addColumn(fieldDesc, true, false); 235 } 236 237 247 private void addColumn(LocalFieldDesc fieldDesc, boolean add, boolean projection) { 248 249 for (Iterator iter = fieldDesc.getColumnElements(); iter.hasNext(); ) { 256 ColumnElement columnElement = (ColumnElement) iter.next(); 257 QueryTable table = findQueryTable(columnElement.getDeclaringTable()); 258 259 if (table == null) 260 table = addQueryTable(columnElement.getDeclaringTable(), null); 261 262 SelectStatement statement = (SelectStatement) getStatement(table); 263 264 if (statement == null) 265 statement = (SelectStatement) addStatement(table); 266 267 if (add) { 268 ColumnRef columnRef = statement.addColumn(columnElement, table); 269 if (resultDesc == null) { 271 resultDesc = new ResultDesc(config, aggregateResultType); 272 } 273 resultDesc.addField(fieldDesc, columnRef, projection); 274 } 275 } 276 } 277 278 288 private void processForeignFields(ArrayList foreignFields, 289 ArrayList localFields) { 290 if (foreignFields.size() == 0) { 291 return; 292 } 293 294 boolean debug = logger.isLoggable(Logger.FINEST); 295 296 if (debug) { 297 logger.finest("sqlstore.sql.generator.selectqueryplan.processforeignfield", config.getPersistenceCapableClass().getName()); 299 } 300 301 foreignPlans = new ArrayList(); 302 303 for (int i = 0; i < foreignFields.size(); i++) { 304 processForeignField((ConstraintFieldName) foreignFields.get(i), localFields); 305 } 306 307 if (debug) { 308 logger.finest("sqlstore.sql.generator.selectqueryplan.processforeignfield.exit"); } 310 } 311 312 321 private void processForeignField(ConstraintFieldName cfn, 322 ArrayList localFields) { 323 324 SelectQueryPlan fp = new SelectQueryPlan(cfn.desc, store, concurrency); 325 326 fp.prefetched = cfn.isPrefetched(); 327 if (fp.prefetched) { 328 fp.options |= RetrieveDescImpl.OPT_ADD_FETCHGROUPS; 330 } 331 332 fp.processParentField(config, cfn.name); 333 fp.build(); 334 335 for (int i = 0; i < fp.parentField.localFields.size(); i++) { 340 LocalFieldDesc la = (LocalFieldDesc) fp.parentField.localFields.get(i); 341 342 if (!getFieldMask(la.absoluteID)) { 343 if ((options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0) { 344 localFields.add(la); 347 } else { 348 addTable(la); 351 } 352 } 353 } 354 foreignPlans.add(fp); 355 } 356 357 private boolean getGroupMask(int groupID) { 358 if (groupID >= FieldDesc.GROUP_DEFAULT) 359 return hierarchicalGroupMask.get(groupID); 360 else if (groupID < FieldDesc.GROUP_NONE) 361 return independentGroupMask.get(-(groupID + 1)); 362 363 return true; 364 } 365 366 private void setGroupMask(int groupID) { 367 if (groupID >= FieldDesc.GROUP_DEFAULT) 368 hierarchicalGroupMask.set(groupID); 369 else if (groupID < FieldDesc.GROUP_NONE) 370 independentGroupMask.set(-(groupID + 1)); 371 } 372 373 390 private void addFetchGroup(int groupID, 391 ArrayList localFields, 392 ArrayList foreignFields) { 393 assert (options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0; 395 396 ArrayList group = config.getFetchGroup(groupID); 397 setGroupMask(groupID); 398 399 if (group != null) { 400 for (int i = 0; i < group.size() ; i++) { 401 FieldDesc f = (FieldDesc) group.get(i); 402 403 if (!getFieldMask(f.absoluteID)) { 404 final boolean isLocalField = f instanceof LocalFieldDesc; 405 setFieldMask(f.absoluteID); 407 408 if (isLocalField) { 409 if ((options & RetrieveDescImpl.OPT_ADD_KEYS_ONLY) == 0 || f.isKeyField()) { 410 int indexToInsert = ( f.isKeyField() ? 0 : localFields.size() ); 416 localFields.add(indexToInsert, f); 417 } 418 } else { 419 if ( (options & RetrieveDescImpl.OPT_PROJECTION) > 0 && 423 (options & RetrieveDescImpl.OPT_ADD_KEYS_ONLY) == 0 && 424 (options & RetrieveDescImpl.OPT_DISABLE_RELATIONSHIP_PREFETCH) == 0 ) { 425 ForeignFieldDesc ff = (ForeignFieldDesc) f; 427 RetrieveDescImpl desc = (RetrieveDescImpl) 428 store.getRetrieveDesc(ff.foreignConfig.getPersistenceCapableClass()); 429 foreignFields.add(new ConstraintFieldName(ff.getName(), desc, true)); 430 } 431 } 432 } 433 } 434 } 435 } 436 437 448 private void addFetchGroups(int groupID, 449 ArrayList localFields, 450 ArrayList foreignFields) { 451 452 if (groupID >= FieldDesc.GROUP_DEFAULT) { 453 for (int i = FieldDesc.GROUP_DEFAULT; i <= groupID; i++) { 455 if (!getGroupMask(i)) { 456 addFetchGroup(i, localFields, foreignFields); 457 } 458 } 459 } else if (groupID < FieldDesc.GROUP_NONE) { 460 if (!getGroupMask(FieldDesc.GROUP_DEFAULT)) { 461 addFetchGroup(FieldDesc.GROUP_DEFAULT, localFields, foreignFields); 463 } 464 465 if (!getGroupMask(groupID)) { 466 addFetchGroup(groupID, localFields, foreignFields); 467 } 468 } 469 } 470 471 485 private void processFetchGroups(ArrayList localFields, ArrayList foreignFields) { 486 487 if ((options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0) { 488 int requestedItems = localFields.size() + foreignFields.size(); 489 490 if (!getGroupMask(FieldDesc.GROUP_DEFAULT)) { 492 addFetchGroups(FieldDesc.GROUP_DEFAULT, localFields, foreignFields); 493 } 494 495 if (requestedItems > 0) { 496 for (int i = 0; i < localFields.size(); i++) { 497 FieldDesc f = (FieldDesc) localFields.get(i); 498 499 setFieldMask(f.absoluteID); 500 501 if (f.fetchGroup != FieldDesc.GROUP_NONE) { 502 if (!getGroupMask(f.fetchGroup)) { 503 addFetchGroups(f.fetchGroup, localFields, foreignFields); 504 } 505 } 506 } 507 508 for (int i = 0; i < foreignFields.size(); i++) { 509 ConstraintFieldName cfn = (ConstraintFieldName) foreignFields.get(i); 510 FieldDesc f = config.getField(cfn.name); 511 512 setFieldMask(f.absoluteID); 513 514 if (f.fetchGroup != FieldDesc.GROUP_NONE) { 515 if (!getGroupMask(f.fetchGroup)) { 516 addFetchGroups(f.fetchGroup, localFields, foreignFields); 517 } 518 } 519 } 520 } 521 } 522 } 523 524 530 private void processLocalFields(ArrayList localFields, LocalFieldDesc projectionField) { 531 boolean debug = logger.isLoggable(Logger.FINEST); 532 533 if (debug) { 534 logger.finest("sqlstore.sql.generator.selectqueryplan.processlocalfield", config.getPersistenceCapableClass().getName()); 536 } 537 538 for (int i = 0; i < localFields.size(); i++) { 539 LocalFieldDesc lf = (LocalFieldDesc) localFields.get(i); 540 addColumn(lf, true, (projectionField == lf)); 541 } 542 543 if (debug) { 544 logger.finest("sqlstore.sql.generator.selectqueryplan.processlocalfield.exit"); } 546 } 547 548 private void joinSecondaryTableStatement(SelectStatement statement, 549 SelectStatement secondaryTableStatement) { 550 statement.copyColumns(secondaryTableStatement); 551 552 QueryTable secondaryTable = (QueryTable) secondaryTableStatement.getQueryTables().get(0); 553 ReferenceKeyDesc key = secondaryTable.getTableDesc().getPrimaryTableKey(); 554 555 addJoinConstraint(this, this, 556 key.getReferencedKey().getColumns(), 557 key.getReferencingKey().getColumns(), ActionDesc.OP_LEFTJOIN); 558 559 secondaryTableStatement.markJoined(); 560 } 561 562 private void processRelatedStatements(SelectStatement statement) { 563 ArrayList secondaryTableStatements = statement.getSecondaryTableStatements(); 564 565 if (secondaryTableStatements != null) { 566 for (int i = 0; i < secondaryTableStatements.size(); i++) { 567 SelectStatement secondaryTableStatement = (SelectStatement) secondaryTableStatements.get(i); 568 569 if (!secondaryTableStatement.isJoined()) { 570 processRelatedStatements(secondaryTableStatement); 571 joinSecondaryTableStatement(statement, secondaryTableStatement); 572 } 573 } 574 575 secondaryTableStatements.clear(); 576 } 577 } 578 579 protected void processStatements() { 580 boolean debug = logger.isLoggable(Logger.FINEST); 581 582 if (debug) { 583 Object [] items = new Object [] {config.getPersistenceCapableClass().getName(), 584 new Integer (statements.size())}; 585 logger.finest("sqlstore.sql.generator.selectqueryplan.processstmts",items); } 587 588 if (concurrency != null) { 589 concurrency.select(this); 590 } 591 592 int size = statements.size(); 593 594 if (size > 1) { 595 super.processStatements(); 596 597 for (int i = 0; i < size; i++) { 598 SelectStatement s = (SelectStatement) statements.get(i); 599 600 if (!s.isJoined()) 601 processRelatedStatements(s); 602 } 603 604 for (int i = 0; i < statements.size(); i++) { 606 SelectStatement s = (SelectStatement) statements.get(i); 607 608 if (s.isJoined()) { 609 statements.remove(i); 610 i--; 611 continue; 612 } 613 } 614 } 615 616 if (debug) { 617 logger.finest("sqlstore.sql.generator.selectqueryplan.processstmts.exit"); } 619 } 620 621 622 629 private void processLocalConstraints() { 630 List stack = constraint.getConstraints(); 631 632 for (int i = 0; i < stack.size(); i++) { 633 ConstraintNode node = (ConstraintNode) stack.get(i); 634 635 if (node instanceof ConstraintFieldName) { 636 ConstraintFieldName fieldNode = (ConstraintFieldName) node; 637 638 if (fieldNode.originalPlan == null) { 639 SelectQueryPlan thePlan = null; 641 642 if (fieldNode.desc == null) { 643 thePlan = this; 644 } else { 645 RetrieveDescImpl rd = (RetrieveDescImpl) fieldNode.desc; 648 thePlan = newForeignConstraintPlan(rd, fieldNode.name); 649 } 650 651 fieldNode.originalPlan = thePlan; 652 653 if (fieldNode.name != null) { 655 FieldDesc field = thePlan.config.getField(fieldNode.name); 656 657 if (field instanceof LocalFieldDesc) { 658 663 thePlan.addTable((LocalFieldDesc) field); 664 } 665 } 666 } 667 } 668 } 669 } 670 671 684 private SelectQueryPlan newForeignConstraintPlan(RetrieveDescImpl rd, 685 String fieldName) { 686 687 SelectQueryPlan fcp = rd.getPlan(); 688 689 if (fcp == null) { 690 fcp = new SelectQueryPlan(rd, store, null); 691 } 692 if (fieldName == null) { 695 return fcp; 696 } 697 698 if (foreignConstraintPlans == null) { 699 foreignConstraintPlans = new HashMap(); 700 } 701 702 SelectQueryPlan masterPlan = null; 703 704 Object tag = (rd.getNavigationalId() != null) ? rd.getNavigationalId() : fieldName; 705 706 if ((masterPlan = (SelectQueryPlan) foreignConstraintPlans.get(tag)) != null) { 707 fcp.tables = masterPlan.tables; 709 fcp.foreignConstraintPlans = masterPlan.foreignConstraintPlans; 710 } else { 711 foreignConstraintPlans.put(tag, fcp); 712 fcp.foreignConstraintPlans = new HashMap(); 713 } 714 715 return fcp; 716 } 717 718 727 private void addCorrelatedExistsQuery(ForeignFieldDesc ff, int operation) { 728 729 Class classType = (ff.cardinalityUPB > 1) ? ff.getComponentType() : ff.getType(); 730 RetrieveDescImpl rd = (RetrieveDescImpl) store.getRetrieveDesc(classType); 731 732 SelectQueryPlan subqueryPlan = new CorrelatedExistSelectPlan(rd, store, ff, this); 733 subqueryPlan.build(); 734 735 addQueryTables(subqueryPlan.tables); 737 738 ConstraintSubquery subqueryConstraint = new ConstraintSubquery(); 739 subqueryConstraint.operation = operation; 740 subqueryConstraint.plan = subqueryPlan; 741 742 constraint.stack.add(subqueryConstraint); 743 } 744 745 752 private void processForeignConstraints() { 753 List currentStack = constraint.getConstraints(); 754 constraint.stack = new ArrayList(); 755 int index = 0; 756 757 while (index < currentStack.size()) { 758 ConstraintNode node = (ConstraintNode) currentStack.get(index); 759 760 if (node instanceof ConstraintForeignFieldName) { 761 processForeignFieldConstraint((ConstraintForeignFieldName) node); 762 763 } else if (node instanceof ConstraintFieldName) { 764 index = processLocalFieldConstraint((ConstraintFieldName) node, currentStack, index); 765 766 } else if (node instanceof ConstraintFieldNameSubQuery) { 767 addCorrelatedInQuery((ConstraintFieldNameSubQuery) node); 768 769 } else { 770 constraint.stack.add(node); 771 } 772 773 index++; 774 } 775 } 776 777 786 private void processForeignFieldConstraint(ConstraintForeignFieldName node) { 787 RetrieveDescImpl rd = (RetrieveDescImpl) node.desc; 788 789 if (rd == null) { 790 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 791 "sqlstore.constraint.noretrievedesc", node.name, config.getPersistenceCapableClass().getName())); 793 } 794 795 SelectQueryPlan fcp = newForeignConstraintPlan(rd, node.name); 796 797 if ((fcp.status & ST_JOINED) == 0) { 798 fcp.processParentField(config, node.name); 799 processJoin(fcp, ActionDesc.OP_EQUIJOIN); 801 fcp.appendAndOp = true; 802 } else { 803 fcp.appendAndOp = false; 804 } 805 } 806 807 817 private int processLocalFieldConstraint(ConstraintFieldName node, 818 List currentStack, 819 int index) { 820 if (node.desc != null) { 821 SelectQueryPlan fcp = ((RetrieveDescImpl) node.desc).getPlan(); 822 823 constraint.stack.add(node); 824 825 if ((fcp.status & ST_JOINED) == 0) { 826 fcp.appendAndOp = true; 827 } else { 831 839 constraint.stack.add(currentStack.get(++index)); 841 constraint.stack.add(currentStack.get(++index)); 842 if (fcp.appendAndOp) { 843 constraint.addOperation(ActionDesc.OP_AND); 844 fcp.appendAndOp = false; 845 } 846 } 847 } else { 848 index = processForeignFieldNullComparision(node, currentStack, index); 849 } 850 return index; 851 } 852 853 860 private int processForeignFieldNullComparision(ConstraintFieldName node, 861 List currentStack, 862 int index) { 863 boolean addCurrentNode = true; 864 if (node.name != null) { 865 FieldDesc f = config.getField(node.name); 867 868 if (f instanceof ForeignFieldDesc && (index + 1 < currentStack.size())) { 869 ConstraintNode nextNode = (ConstraintNode) currentStack.get(++index); 870 if ((nextNode instanceof ConstraintOperation) && 871 ((((ConstraintOperation) nextNode).operation == ActionDesc.OP_NULL) || 872 (((ConstraintOperation) nextNode).operation == ActionDesc.OP_NOTNULL))) { 873 874 processNullConstraint((ForeignFieldDesc) f, nextNode); 875 } else { 876 constraint.stack.add(node); 877 constraint.stack.add(nextNode); 878 } 879 addCurrentNode = false; 881 } 882 } 883 if (addCurrentNode) { 884 constraint.stack.add(node); 885 } 886 return index; 887 } 888 889 898 private void processNullConstraint(ForeignFieldDesc ff, ConstraintNode nextNode) { 899 900 if (ff.hasForeignKey()) { 901 ArrayList localFields = ff.getLocalFields(); 903 904 for (int j = 0; j < localFields.size(); j++) { 905 constraint.stack.add(new ConstraintFieldDesc((LocalFieldDesc) localFields.get(j))); 906 constraint.stack.add(nextNode); 907 } 908 } else { 909 int subOp = ActionDesc.OP_NOTEXISTS; 911 912 if (((ConstraintOperation) nextNode).operation == ActionDesc.OP_NOTNULL) { 913 subOp = ActionDesc.OP_EXISTS; 914 } 915 916 addCorrelatedExistsQuery(ff, subOp); 918 } 919 } 920 921 929 private void addCorrelatedInQuery(ConstraintFieldNameSubQuery node) { 930 FieldDesc field = config.getField(node.fieldName); 931 RetrieveDescImpl rd = (RetrieveDescImpl) node.desc; 932 933 if (field != null && field instanceof ForeignFieldDesc) { 934 ForeignFieldDesc ff = (ForeignFieldDesc) field; 935 936 if (ff.getComponentType() != rd.getPersistenceCapableClass() ) { 937 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 938 "core.constraint.unknownfield", node.fieldName, rd.getPersistenceCapableClass().getName())); 940 } 941 942 SelectQueryPlan subqueryPlan = new CorrelatedInSelectPlan(rd, store, ff, this); 943 subqueryPlan.build(); 944 945 addQueryTables(subqueryPlan.tables); 947 948 ConstraintSubquery subqueryConstraint = new ConstraintSubquery(); 950 subqueryConstraint.plan = subqueryPlan; 951 constraint.stack.add(subqueryConstraint); 952 953 ArrayList localFields = ff.getLocalFields(); 954 for (int i = 0; i < localFields.size(); i++) { 956 constraint.addField((LocalFieldDesc) localFields.get(i), this); 957 } 958 } else { 959 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 962 "core.constraint.unknownfield", node.fieldName, rd.getPersistenceCapableClass().getName())); 964 } 965 } 966 967 977 private void processUnboundConstraints() { 978 List currentStack = constraint.getConstraints(); 979 constraint.stack = new ArrayList(); 980 981 for (int i = 0; i < currentStack.size(); i++) { 982 ConstraintNode node = (ConstraintNode) currentStack.get(i); 983 984 if (node instanceof ConstraintFieldName) { 985 ConstraintFieldName fieldNode = (ConstraintFieldName) node; 986 987 if (fieldNode.name != null) { 988 constraint.stack.add(fieldNode); 989 } else if (fieldNode.desc != null) { 990 SelectQueryPlan fcp = ((RetrieveDescImpl) fieldNode.desc).getPlan(); 991 992 if ((fcp.status & ST_JOINED) == 0) { 994 fcp.appendAndOp = false; 997 998 processJoin(fcp, ActionDesc.OP_NONREL_JOIN); 999 } 1000 } 1001 } else { 1002 constraint.stack.add(node); 1003 } 1004 } 1005 } 1006 1007 1015 private void processJoin(SelectQueryPlan fcp, int joinOp) { 1016 fcp.processConstraints(); 1017 doJoin(fcp, joinOp); 1018 } 1019 1020 1028 private void processParentField(ClassDesc parentConfig, String fieldName) { 1029 if (parentField == null) { 1030 FieldDesc f = parentConfig.getField(fieldName); 1032 1033 if (f == null || !(f instanceof ForeignFieldDesc)) { 1034 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 1035 "core.constraint.unknownfield", fieldName, parentConfig.getPersistenceCapableClass().getName())); 1037 } 1038 parentField = (ForeignFieldDesc) f; 1039 1040 if (parentField.useJoinTable()) { 1042 for (int i = 0; i < parentField.assocLocalColumns.size(); i++) { 1047 ColumnElement col = (ColumnElement) parentField.assocLocalColumns.get(i); 1048 addQueryTable(col.getDeclaringTable(), config); 1049 } 1050 } 1051 1052 for (int i = 0; i < parentField.foreignColumns.size(); i++) { 1056 ColumnElement col = (ColumnElement) parentField.foreignColumns.get(i); 1057 addQueryTable(col.getDeclaringTable(), config); 1058 } 1059 } 1060 } 1061 1062 1066 public void build() { 1067 if ((status & ST_BUILT) > 0) { 1069 return; 1070 } 1071 1072 processFields(); 1073 1074 processConstraints(); 1075 1076 processJoins(); 1077 1078 processOrderConstraints(); 1079 1080 status |= ST_BUILT; 1081 } 1082 1083 1087 protected void processFields() { 1088 ArrayList foreignFields = new ArrayList(); 1089 ArrayList localFields = new ArrayList(); 1090 1091 LocalFieldDesc projectionField = separateFieldList(localFields, foreignFields); 1092 1093 processFetchGroups(localFields, foreignFields); 1096 1097 processForeignFields(foreignFields, localFields); 1100 processLocalFields(localFields, projectionField); 1101 } 1102 1103 1113 private LocalFieldDesc separateFieldList(ArrayList localFields, 1114 ArrayList foreignFields) { 1115 1116 LocalFieldDesc projectionField = null; 1117 1118 while (fieldIterator.hasNext()) { 1119 ConstraintFieldName cfn = (ConstraintFieldName) fieldIterator.next(); 1120 FieldDesc f = config.getField(cfn.name); 1121 1122 if (f == null) { 1123 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 1124 "core.constraint.unknownfield", cfn.name, config.getPersistenceCapableClass().getName())); 1126 } 1127 1128 setFieldMask(f.absoluteID); 1129 1130 if (cfn.desc != null) { 1131 foreignFields.add(cfn); 1132 } else { 1133 localFields.add(f); 1134 if (cfn.isProjection()) { 1135 projectionField = (LocalFieldDesc) f; 1136 } 1137 } 1138 } 1139 1140 return projectionField; 1141 } 1142 1143 protected void processConstraints() { 1144 if ((status & ST_BUILT) > 0 || (status & ST_C_BUILT) > 0) { 1146 return; 1147 } 1148 1149 processLocalConstraints(); 1150 1151 processStatements(); 1153 1154 processForeignConstraints(); 1155 1156 processUnboundConstraints(); 1158 1159 status |= ST_C_BUILT; 1160 } 1161 1162 1171 private void doJoin(SelectQueryPlan foreignPlan, int joinOperation) { 1172 if ((foreignPlan.status & ST_JOINED) > 0) { 1173 return; 1174 } 1175 1176 mergeConstraints(foreignPlan, joinOperation); 1177 1178 mergeStatements(foreignPlan, joinOperation); 1179 1180 if (foreignPlan.tables != null) { 1181 addQueryTables(foreignPlan.tables); 1182 } 1183 1184 foreignPlan.status = foreignPlan.status | ST_JOINED; 1185 } 1186 1187 1195 private void mergeStatements(SelectQueryPlan foreignPlan, int joinOperation) { 1196 SelectStatement fromStatement; 1197 SelectStatement toStatement; 1198 1199 if (foreignPlan.statements.size() > 0) { 1200 toStatement = (SelectStatement) foreignPlan.statements.get(0); 1201 1202 if (statements.size() > 0) { 1204 fromStatement = (SelectStatement) statements.get(0); 1205 1206 fromStatement.copyColumns(toStatement); 1208 1209 if (joinOperation == ActionDesc.OP_NONREL_JOIN) { 1213 fromStatement.tableList.addAll(toStatement.tableList); 1214 } 1215 1216 mergeResultDesc(foreignPlan); 1217 if (foreignPlan.prefetched) { 1218 resultDesc.setPrefetching(); 1221 } 1222 1223 this.options |= foreignPlan.options; 1224 } 1225 } 1226 } 1227 1228 1237 private void mergeConstraints(SelectQueryPlan foreignPlan, int joinOperation) { 1238 1239 if (joinOperation != ActionDesc.OP_NONREL_JOIN) { 1240 if (foreignPlan.parentField.useJoinTable()) { 1242 addJoinConstraint(this, foreignPlan, 1245 foreignPlan.parentField.localColumns, 1246 foreignPlan.parentField.assocLocalColumns, joinOperation); 1247 1248 addJoinConstraint(foreignPlan, foreignPlan, 1249 foreignPlan.parentField.assocForeignColumns, 1250 foreignPlan.parentField.foreignColumns, joinOperation); 1251 1252 if (joinOperation == ActionDesc.OP_EQUIJOIN) { 1255 constraint.addOperation(ActionDesc.OP_AND); 1256 } 1257 } else { 1258 addJoinConstraint(this, foreignPlan, 1259 foreignPlan.parentField.localColumns, 1260 foreignPlan.parentField.foreignColumns, joinOperation); 1261 } 1262 } 1263 1264 boolean addAnd = constraint.mergeConstraint(foreignPlan.constraint, joinOperation); 1266 1267 if (addAnd || foreignPlan.appendAndOp) { 1268 constraint.addOperation(ActionDesc.OP_AND); 1269 } 1270 } 1271 1272 1278 private void mergeResultDesc(SelectQueryPlan foreignPlan) { 1279 ResultDesc foreignResult = foreignPlan.resultDesc; 1280 1281 if (resultDesc != null && foreignResult != null) { 1282 resultDesc.doJoin(foreignResult, foreignPlan.parentField); 1283 } else if (resultDesc == null) { 1284 resultDesc = foreignResult; 1285 } 1286 } 1287 1288 1297 protected void addJoinConstraint(SelectQueryPlan fromPlan, 1298 SelectQueryPlan toPlan, 1299 ArrayList fromColumns, 1300 ArrayList toColumns, 1301 int joinOp) { 1302 1303 ConstraintJoin join = new ConstraintJoin(); 1304 1305 join.operation = joinOp; 1306 join.fromColumns = fromColumns; 1307 join.fromPlan = fromPlan; 1308 join.toColumns = toColumns; 1309 join.toPlan = toPlan; 1310 1311 constraint.addJoinConstraint(join); 1312 } 1313 1314 1323 private void processJoins() { 1324 1325 if (foreignPlans == null) { 1326 return; 1327 } 1328 1329 for (Iterator iter = foreignPlans.iterator(); iter.hasNext(); ) { 1330 SelectQueryPlan fp = (SelectQueryPlan) iter.next(); 1331 1332 if ((fp.status & ST_JOINED) == 0) { 1333 fp.processJoins(); 1335 1336 if (statements.size() == 1 && fp.statements.size() == 1) { 1338 doJoin(fp, getJoinOperator(fp)); 1339 } 1340 } 1341 1342 if ((fp.status & ST_JOINED) > 0) { 1343 iter.remove(); 1345 } 1346 } 1347 1348 if (foreignPlans != null && foreignPlans.size() > 0) { 1350 1351 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 1352 "sqlstore.sql.generator.selectqueryplan.plansnotjoined")); } else { 1354 foreignPlans = null; 1355 } 1356 } 1357 1358 1368 private int getJoinOperator(SelectQueryPlan dependentPlan) { 1369 int joinOperator; 1370 ForeignFieldDesc parentField = null; 1371 1372 if (isProjection(this)) { 1373 parentField = dependentPlan.parentField; 1374 } else if (isProjection(dependentPlan)) { 1375 parentField = dependentPlan.parentField.getInverseRelationshipField(); 1376 } 1377 1378 if (parentField != null) { 1379 1380 joinOperator = ActionDesc.OP_LEFTJOIN; 1381 } else { 1399 joinOperator = ActionDesc.OP_EQUIJOIN; 1400 } 1401 1402 return joinOperator; 1403 } 1404 1405 private boolean isProjection(SelectQueryPlan plan) { 1406 return(prefetched 1407 || (plan.options & RetrieveDescImpl.OPT_PROJECTION) > 0 1408 && (plan.options & RetrieveDescImpl.OPT_AGGREGATE) == 0); 1409 } 1410 1411 1428 public void processOrderConstraints() { 1429 1430 if ((status & ST_BUILT) > 0 || (status & ST_OC_BUILT) > 0) { 1431 return; 1432 } 1433 1434 ArrayList orderByArray = new ArrayList(); 1435 1436 int i, pos; 1437 int insertAt = 0; 1438 1439 if (constraint != null) { 1443 i = 0; 1444 while (i < constraint.stack.size()) { 1445 ConstraintNode opNode = (ConstraintNode) constraint.stack.get(i); 1446 1447 if ((opNode instanceof ConstraintOperation) 1448 && ((((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY) || 1449 (((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY_DESC))) { 1450 pos = -1; 1451 if ((i > 1) && (constraint.stack.get(i - 2) instanceof ConstraintValue)) { 1452 pos = ((Integer ) ((ConstraintValue) constraint.stack.get(i - 2)).getValue() ).intValue(); 1453 constraint.stack.remove(i - 2); 1454 i = i - 1; 1455 } 1456 1457 if (pos > 0) { 1458 insertAt = pos; 1459 } 1460 1461 for (int k = orderByArray.size(); k <= insertAt; k++) { 1462 orderByArray.add(null); 1463 } 1464 1465 if (orderByArray.get(insertAt) == null) { 1466 orderByArray.set(insertAt, new ArrayList()); 1467 } 1468 1469 ConstraintNode fieldNode = (ConstraintNode) constraint.stack.get(i - 1); 1470 ConstraintFieldDesc consFieldDesc = null; 1471 1472 if (fieldNode instanceof ConstraintFieldName) { 1473 QueryPlan originalPlan = this; 1474 1475 if (((ConstraintField) fieldNode).originalPlan != null) { 1476 originalPlan = ((ConstraintField) fieldNode).originalPlan; 1477 } 1478 1479 FieldDesc fieldDesc = originalPlan.config. 1480 getField(((ConstraintFieldName) fieldNode).name); 1481 1482 if (!(fieldDesc instanceof LocalFieldDesc)) { 1483 throw new JDOUserException(I18NHelper.getMessage(messages, 1484 "core.generic.notinstanceof", fieldDesc.getClass().getName(), 1486 "LocalFieldDesc")); } 1488 1489 consFieldDesc = new ConstraintFieldDesc((LocalFieldDesc) fieldDesc, 1490 originalPlan, 1); 1491 } else if (fieldNode instanceof ConstraintFieldDesc) { 1492 consFieldDesc = (ConstraintFieldDesc) fieldNode; 1493 } else { 1494 throw new JDOUserException(I18NHelper.getMessage(messages, 1495 "core.generic.notinstanceof", fieldNode.getClass().getName(), 1497 "ConstraintFieldName/ConstraintFieldDesc")); } 1499 1500 if (((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY_DESC) { 1501 consFieldDesc.ordering = -1; 1502 } 1503 1504 ArrayList temp = (ArrayList) (orderByArray.get(insertAt)); 1506 temp.add(consFieldDesc); 1507 1508 constraint.stack.remove(i); 1509 constraint.stack.remove(i - 1); 1510 i = i - 2 + 1; 1511 } 1512 i = i + 1; 1513 } 1514 } 1515 1516 for (int j = 0, size = orderByArray.size(); j < size; j++) { 1517 ArrayList oa = (ArrayList) orderByArray.get(j); 1518 1519 if (constraint == null) { 1520 constraint = new Constraint(); 1521 } 1522 1523 for (int k = 0, sizeK = oa.size(); k < sizeK; k++) { 1524 ConstraintFieldDesc ob = (ConstraintFieldDesc) oa.get(k); 1525 1526 if (ob.ordering < 0) { 1527 constraint.addField(ob); 1528 constraint.addOperation(ActionDesc.OP_ORDERBY_DESC); 1529 } else { 1530 constraint.addField(ob); 1531 constraint.addOperation(ActionDesc.OP_ORDERBY); 1532 } 1533 } 1534 } 1535 1536 status |= ST_OC_BUILT; 1537 } 1538 1539 protected Statement newStatement() { 1540 return new SelectStatement(store.getVendorType(), this); 1541 } 1542 1543 1550 public Object getResult(PersistenceManager pm, ResultSet resultData) 1551 throws SQLException { 1552 return resultDesc.getResult(pm, resultData); 1553 } 1554 1555} 1556 | Popular Tags |