1 2 12 package com.versant.core.jdbc.metadata; 13 14 import com.versant.core.metadata.parser.JdoElement; 15 import com.versant.core.metadata.parser.JdoExtension; 16 import com.versant.core.metadata.parser.JdoExtensionKeys; 17 import com.versant.core.metadata.*; 18 import com.versant.core.common.OID; 19 import com.versant.core.common.State; 20 import com.versant.core.jdbc.*; 21 import com.versant.core.jdbc.query.JdbcJDOQLCompiler; 22 import com.versant.core.jdbc.sql.exp.*; 23 import com.versant.core.server.PersistGraph; 24 import com.versant.core.server.StateContainer; 25 import com.versant.core.common.*; 26 import com.versant.core.util.CharBuf; 27 import com.versant.core.jdo.query.Node; 28 import com.versant.core.jdo.query.VarNode; 29 import com.versant.core.jdo.query.VarNodeIF; 30 import com.versant.core.common.Debug; 31 32 import java.io.PrintStream ; 33 import java.sql.Connection ; 34 import java.sql.SQLException ; 35 import java.sql.PreparedStatement ; 36 import java.sql.ResultSet ; 37 38 import com.versant.core.common.BindingSupportImpl; 39 40 44 public class JdbcFKCollectionField extends JdbcCollectionField { 45 46 49 public JdbcRefField fkField; 50 51 54 private JdbcClass elementJdbcClass; 55 56 private static final int WINDOW_SIZE = 20; 58 private static final float FUDGE_FACTOR = 1.5f; 60 private static final int MIN_LEN = 4; 62 63 protected transient int fetchCount; 65 protected transient float avgRowCount; 67 protected transient int expansionCount; 71 72 public void dump(PrintStream out, String indent) { 73 super.dump(out, indent); 74 String is = indent + " "; 75 out.println(is + "fkField " + fkField); 76 } 77 78 82 public void processMetaData(JdoElement context, JdbcMetaDataBuilder mdb, 83 boolean quiet) { 84 ClassMetaData ecmd = fmd.elementTypeMetaData; 85 elementJdbcClass = (JdbcClass)ecmd.storeClass; 86 if (elementJdbcClass == null) { 87 throw BindingSupportImpl.getInstance().runtime("The inverse extension may only be used for " + 88 "collections of PC instances stored by JDBC\n" + 89 context.getContext()); 90 } 91 ClassMetaData cmd = fmd.classMetaData; 92 93 super.processMetaData(context, mdb, quiet); 94 95 useJoin = JdbcField.USE_JOIN_INNER; 96 if (fmd.category != MDStatics.CATEGORY_ARRAY) { 97 fmd.managed = mdb.getJdbcConfig().managedOneToMany; 98 } else { 99 fmd.managed = false; 100 } 101 102 JdoExtension[] a; 103 if (fmd.category == MDStatics.CATEGORY_ARRAY) { 104 a = fmd.jdoArray.extensions; 105 } else if (fmd.category == MDStatics.CATEGORY_COLLECTION) { 106 a = fmd.jdoCollection.extensions; 107 } else { 108 throw BindingSupportImpl.getInstance().internal( 109 "Category '" 110 + MDStaticUtils.toCategoryString(fmd.category) + "' is not supported for FK Collections"); 111 } 112 int len = a.length; 113 for (int i = 0; i < len; i++) { 114 JdoExtension e = a[i]; 115 switch (e.key) { 116 case JdoExtensionKeys.MANAGED: 117 if (fmd.category == MDStatics.CATEGORY_ARRAY && e.getBoolean()) { 118 throw BindingSupportImpl.getInstance().invalidOperation( 119 "The managed option is not supported for arrays: " + fmd.name); 120 } 121 fmd.managed = e.getBoolean(); 122 break; 123 case JdoExtensionKeys.INVERSE: 124 case JdoExtensionKeys.JDBC_LINK_FOREIGN_KEY: 125 String fname = e.getString(); 126 FieldMetaData f = ecmd.getFieldMetaData(fname); 127 if (f == null) { 128 f = createFakeFKBackRef(cmd, ecmd, mdb, e, quiet); 129 } 130 if (f.isEmbeddedRef()) { 131 throw BindingSupportImpl.getInstance().invalidOperation("an Inverse field may not be Embedded"); 132 } 133 if (f.storeField == null) { 134 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + "' is not persistent\n" + 135 context.getContext()); 136 } 137 if (!(f.storeField instanceof JdbcRefField)) { 138 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + "' is not a reference\n" + 139 context.getContext()); 140 } 141 fkField = (JdbcRefField)f.storeField; 142 if (!cmd.isAncestorOrSelf(fkField.targetClass)) { 143 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + "' references " + 144 fkField.targetClass + " and not our class\n" + 145 context.getContext()); 146 } 147 fmd.ordered = false; 148 createIndex(mdb, ecmd, e.nested); 149 break; 150 151 default: 152 if (e.isJdbc()) { 153 throw BindingSupportImpl.getInstance().runtime( 154 "Unexpected extension: " + e + "\n" + e.getContext()); 155 } 156 } 157 } 158 if (fkField == null) { 159 throw BindingSupportImpl.getInstance().internal("fkField is null"); 160 } 161 162 fkField.masterCollectionField = this; 163 ourPkColumns = fkField.cols; 164 } 165 166 private FieldMetaData createFakeFKBackRef(ClassMetaData cmd, 167 ClassMetaData ecmd, JdbcMetaDataBuilder mdb, 168 JdoExtension e, boolean quiet) { 169 fmd.managed = false; 170 171 FieldMetaData f = new FieldMetaData(); 172 f.fake = true; 173 f.typeMetaData = cmd; 174 f.name = cmd.getShortName() + "_" + fmd.name; 175 f.category = MDStatics.CATEGORY_REF; 176 f.ordered = false; 177 f.managed = false; 178 f.primaryField = true; 179 JdbcRefField jdbcRefField = new JdbcRefField(); 180 jdbcRefField.targetClass = cmd; 181 fkField = jdbcRefField; 182 f.classMetaData = ecmd; 183 jdbcRefField.fmd = f; 184 f.storeField = jdbcRefField; 185 jdbcRefField.fake = true; 186 f.type = cmd.cls; 187 f.inverseFieldMetaData = fmd; 188 mdb.processRefFieldImpl(elementJdbcClass, jdbcRefField, 189 f, e, e.nested, quiet); 190 191 mdb.getClassInfo(ecmd).elements.add(f.storeField); 204 return f; 205 } 206 207 210 private void createIndex(JdbcMetaDataBuilder mdb, ClassMetaData refCmd, 211 JdoExtension[] nested) { 212 JdbcClass refJdbcClass = (JdbcClass)refCmd.storeClass; 213 JdbcIndex idx = null; 214 boolean doNotCreateIndex = false; 215 216 int n = nested == null ? 0 : nested.length; 217 for (int i = 0; i < n; i++) { 218 JdoExtension e = nested[i]; 219 switch (e.key) { 220 case JdoExtensionKeys.JDBC_INDEX: 221 if (idx != null) { 222 throw BindingSupportImpl.getInstance().runtime("Only one jdbc-index extension is allowed here\n" + 223 e.getContext()); 224 } 225 if (e.isNoValue()) { 226 doNotCreateIndex = true; 227 break; 228 } 229 idx = new JdbcIndex(); 230 idx.name = e.value; 231 break; 232 case JdoExtensionKeys.JDBC_COLUMN: 233 case JdoExtensionKeys.JDBC_USE_JOIN: 234 case JdoExtensionKeys.JDBC_CONSTRAINT: 235 case JdoExtensionKeys.JDBC_REF: 236 break; 238 default: 239 if (e.isJdbc()) { 240 MetaDataBuilder.throwUnexpectedExtension(e); 241 } 242 } 243 } 244 245 if (doNotCreateIndex) return; 246 if (idx == null) idx = new JdbcIndex(); 247 if (fkField.cols != null) { 248 idx.setCols(fkField.cols); 249 } 250 251 if (idx.name != null) { 254 try { 255 mdb.getNameGenerator().addIndexName( 256 refJdbcClass.table.name, idx.name); 257 } catch (IllegalArgumentException x) { 258 throw BindingSupportImpl.getInstance().runtime(x.getMessage(), 259 x); 260 } 261 } 262 263 mdb.getClassInfo(refCmd).autoIndexes.add(idx); 264 } 265 266 270 public void persistPass2Block(PersistGraph graph, int blockStart, 271 int blockEnd, CharBuf s, Connection con, boolean batchInserts, 272 boolean batchUpdates) throws SQLException { 273 } 275 276 279 public int fetch(JdbcStorageManager sm, OID oid, State state, 280 FetchGroupField field, boolean forUpdate, 281 StateContainer container, boolean fetchPass2Fields, 282 ColFieldHolder colFHolder) 283 throws SQLException { 284 285 String sql = forUpdate ? field.jdbcSelectSqlForUpdate : field.jdbcSelectSql; 286 final boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO; 287 288 FetchGroup nextFetchGroup = field.nextFetchGroup; 289 FgDs[] fgDses = new FgDs[1]; 290 291 if (sql == null) { 292 SelectExp se = getSelectExp(field, sm, fgDses); 293 CharBuf s = sm.generateSql(se); 294 sql = s.toString(); 295 if (forUpdate) { 296 field.jdbcSelectSqlForUpdate = sql; 297 } else { 298 field.jdbcSelectSql = sql; 299 } 300 } else { 301 fgDses[0] = ((JdbcFetchGroup)nextFetchGroup.storeFetchGroup).getExistingFgDs(true, false); 302 } 303 304 if (colFHolder != null && fgDses[0] != null) { 305 colFHolder.valueJs = fgDses[0].getJoinStruct(); 306 } 307 308 PreparedStatement ps = null; 309 ResultSet rs = null; 310 Struct s = new Struct(); 311 try { 312 ps = sm.con().prepareStatement(sql); 313 ((JdbcOID)oid).setParams(ps, 1); 314 try { 315 rs = ps.executeQuery(); 316 } catch (Exception e) { 317 throw mapException(e, 318 "Fetch inverse foreign key collection failed: " + 319 JdbcUtils.toString(e) + "\n" + 320 "Field: " + fmd.getTypeQName() + "\n" + 321 "Instance: " + oid.toSString() + "\n" + 322 JdbcUtils.getPreparedStatementInfo(sql, ps)); 323 } 324 325 s.init(); 326 327 ClassMetaData valueCmd = fmd.elementTypeMetaData; 328 329 int valuePkLen = 0; 330 if (joined) valuePkLen = elementJdbcClass.table.pkSimpleColumnCount; 331 for (; rs.next();) { 332 OID valueOid = valueCmd.createOID(false); 333 boolean isNull = !((JdbcOID)valueOid).copyKeyFields(rs, 1); 334 if (isNull) { 335 s.add(null); 336 } else { 337 s.add(valueOid); 338 } 339 340 if (!isNull && joined && container.isStateRequired(valueOid, 341 nextFetchGroup)) { 342 State valueState = sm.createStateImp(rs, valueOid, 343 nextFetchGroup, forUpdate, 1 + valuePkLen, 344 null, true, container, 345 fgDses[0], fetchPass2Fields, false, null); 346 container.addState(valueOid, valueState); 347 } 348 } 349 350 updateState(s, state); 353 updateStats(s.size); 354 } finally { 355 cleanup(rs); 356 cleanup(ps); 357 } 358 return s.size; 359 } 360 361 public int fetchFrom(ResultSet rs, OID oid, State state, 362 FetchGroupField field, boolean forUpdate, 363 StateContainer container, 364 boolean fetchPass2Fields, int colIndex, 365 FetchInfo fetchInfo, JdbcStorageManager sm) 366 throws SQLException { 367 368 Struct s = new Struct(); 369 final boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO; 370 boolean first = true; 371 s.init(); 372 ClassMetaData valueCmd = fmd.elementTypeMetaData; 373 374 FetchGroup nextFetchGroup = field.nextFetchGroup; 375 376 int valuePkLen = 0; 377 if (joined) valuePkLen = elementJdbcClass.table.pkSimpleColumnCount; 378 for (; ;) { 379 boolean mustBreak = false; 380 if (first) { 381 first = false; 382 mustBreak = updateForFirstRow(fetchInfo, mustBreak, rs, 383 colIndex, oid); 384 } else { 385 if (rs.next()) { 386 mustBreak = checkKeyOid(rs, colIndex, fetchInfo, mustBreak, 387 oid); 388 fetchInfo.onNextRow = true; 389 } else { 390 fetchInfo.onNextRow = false; 391 fetchInfo.finished = true; 392 mustBreak = true; 393 } 394 } 395 if (mustBreak) break; 396 397 OID valueOid = valueCmd.createOID(false); 398 boolean isNull = !((JdbcOID)valueOid).copyKeyFields(rs, 399 colIndex + ourPkColumns.length); 400 if (!isNull) { 401 s.add(valueOid); 402 if (joined && container.isStateRequired(valueOid, 403 nextFetchGroup)) { 404 State valueState = sm.createStateImp(rs, valueOid, 405 nextFetchGroup, forUpdate, colIndex + ourPkColumns.length + valuePkLen, 406 null, true, container, 407 ((JdbcFetchGroup)nextFetchGroup.storeFetchGroup).getExistingFgDs(true, true), 408 fetchPass2Fields, 409 false, null); 410 container.addState(valueOid, valueState); 411 } 412 } else { 413 break; 415 } 416 } 417 418 updateState(s, state); 419 updateStats(s.size); 420 return s.size; 421 } 422 423 private void updateStats(int size) { 424 int fc = ++fetchCount; 427 if (fc > WINDOW_SIZE) { 428 fc = WINDOW_SIZE; 429 } else if (fc == 1) { 430 avgRowCount = size; 431 } else if (fc < 0) { 432 fc = fetchCount = WINDOW_SIZE; 433 } else { 434 avgRowCount = (avgRowCount * (fc - 1) + size) / fc; 435 } 436 } 437 438 public int fetchWithFilter(JdbcStorageManager sm, StateContainer oidStates, 439 FetchGroupField field, ResultSet rs, boolean forUpdate, 440 OID oidToCheckOn, 441 OID[] lastReadStateOID, ClassMetaData cmd, 442 ColFieldHolder colFHolder) 443 throws SQLException { 444 445 ClassMetaData valueCmd = fmd.elementTypeMetaData; 446 final boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO; 447 FetchGroup nextFetchGroup = field.nextFetchGroup; 448 449 if (colFHolder != null) { 450 colFHolder.valueJs = new JoinStructure(nextFetchGroup); 451 } 452 453 int valuePkLen = 0; 454 if (joined) valuePkLen = elementJdbcClass.table.pkSimpleColumnCount; 455 456 int rootOIDLenght = ((JdbcClass)cmd.storeClass).table.pkSimpleColumnCount; 457 int stateOIDPKLen = ((JdbcClass)fmd.classMetaData.storeClass).table.pkSimpleColumnCount; 458 459 OID rootOid = cmd.createOID(false); 461 OID prevRootOid = cmd.createOID(false); 463 OID tmpOID = null; 464 465 OID stateOID = fmd.classMetaData.createOID(false); 466 OID prevStateOID = fmd.classMetaData.createOID(false); 467 OID tmpStateOID = null; 468 469 Struct s = new Struct(); 470 s.init(); 471 472 boolean currentRowValid = false; 473 boolean prevRowValid = false; 474 int returnState = 0; 475 476 FgDs fgDs = ((JdbcFetchGroup)nextFetchGroup.storeFetchGroup).getExistingFgDs( 477 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER); 478 if (colFHolder != null) { 479 colFHolder.valueJs = fgDs.getJoinStruct(); 480 } 481 482 if (lastReadStateOID[0] != null) { 484 int index = 1; 485 486 prevRootOid = lastReadStateOID[0]; 487 index += rootOIDLenght; 488 489 stateOID = lastReadStateOID[1]; 490 index += stateOIDPKLen; 491 492 currentRowValid = oidStates.containsKey(stateOID); 493 494 if (currentRowValid) { 495 returnState |= STATUS_VALID_ROWS; 496 OID valueOid = valueCmd.createOID(false); 497 boolean isNull = !((JdbcOID)valueOid).copyKeyFields(rs, index); 498 index += valuePkLen; 499 500 if (!isNull) { 501 s.add(valueOid); 502 } else { 503 s.add(null); 504 } 505 506 if (!isNull && joined && oidStates.isStateRequired(valueOid, 507 nextFetchGroup)) { 508 509 State valueState = sm.createStateImp(rs, 510 valueOid, 511 nextFetchGroup, forUpdate, index, null, 512 true, oidStates, fgDs, false, false, 513 null); 514 oidStates.addState(valueOid, valueState); 515 } 516 } 517 518 tmpOID = rootOid; 520 rootOid = prevRootOid; 521 prevRootOid = tmpOID; 522 523 tmpStateOID = stateOID; 525 stateOID = prevStateOID; 526 prevStateOID = tmpStateOID; 527 528 prevRowValid = currentRowValid; 529 } 530 531 for (; rs.next();) { 533 int index = 1; 534 ((JdbcOID)rootOid).copyKeyFields(rs, index); 535 index += rootOIDLenght; 536 537 ((JdbcOID)stateOID).copyKeyFields(rs, index); 538 index += stateOIDPKLen; 539 540 currentRowValid = oidStates.containsKey(stateOID); 541 542 if (!stateOID.equals(prevStateOID) && prevRowValid) { 545 if (updateStateFilter(s, oidStates.get(prevStateOID))) { 546 returnState |= STATUS_DATA_ADDED; 547 } 548 updateStatistics(s.size); 549 if (oidToCheckOn.equals(prevRootOid) && !oidToCheckOn.equals( 551 rootOid)) { 552 lastReadStateOID[0] = rootOid; 553 lastReadStateOID[1] = stateOID; 554 returnState |= STATUS_VALID_ROWS; 555 return returnState; 556 } 557 s.init(); 559 } 560 561 if (currentRowValid) { 562 returnState |= STATUS_VALID_ROWS; 563 OID valueOid = valueCmd.createOID(false); 564 boolean isNull = !((JdbcOID)valueOid).copyKeyFields(rs, index); 565 if (!isNull) { 566 s.add(valueOid); 567 } else { 568 s.add(null); 569 } 570 571 index += valuePkLen; 572 if (!isNull && joined && oidStates.isStateRequired(valueOid, 573 nextFetchGroup)) { 574 State valueState = sm.createStateImp(rs, 575 valueOid, 576 nextFetchGroup, forUpdate, index, null, 577 true, oidStates, 578 ((JdbcFetchGroup)nextFetchGroup.storeFetchGroup).getFgDs(true, 579 field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER), 580 false, false, null); 581 oidStates.addState(valueOid, valueState); 582 } 583 } 584 585 586 tmpOID = rootOid; 588 rootOid = prevRootOid; 589 prevRootOid = tmpOID; 590 591 tmpStateOID = stateOID; 593 stateOID = prevStateOID; 594 prevStateOID = tmpStateOID; 595 596 prevRowValid = currentRowValid; 597 } 598 rs.close(); 599 if ((returnState & STATUS_VALID_ROWS) == STATUS_VALID_ROWS) { 600 if (updateStateFilter(s, oidStates.get(prevStateOID))) { 601 returnState |= STATUS_DATA_ADDED; 602 } 603 } 604 returnState |= STATUS_CLOSED; 605 return returnState; 606 } 607 608 public void fillStateWithEmpty(FetchGroupField field, State state) { 609 if (!state.containsField(fmd.stateFieldNo)) { 610 state.setInternalObjectField(fmd.stateFieldNo, 611 PRE_GEN_EMPTY_OBJECT_ARRAY); 612 } 613 } 614 615 private boolean updateState(Struct s, State state) { 616 if (state == null) return false; 617 if (s.values == null) s.values = EMPTY_OID_ARRAY; 618 s.trim(); 619 state.setInternalObjectField(fmd.stateFieldNo, s.values); 620 return true; 621 } 622 623 private boolean updateStateFilter(Struct s, State state) { 624 if (state == null) return false; 625 if (s.values == null) s.values = EMPTY_OID_ARRAY; 626 if (state.getInternalObjectField(fmd.stateFieldNo) == PRE_GEN_EMPTY_OBJECT_ARRAY) { 627 s.trim(); 628 state.setInternalObjectField(fmd.stateFieldNo, s.values); 629 return true; 630 } 631 return false; 632 } 633 634 public void appendOrderExpForFilterExp(SelectExp se, SelectExp root) { 635 if (fmd.elementTypeMetaData != null) { 636 root.appendOrderByForColumns( 637 ((JdbcClass)fmd.elementTypeMetaData.storeClass).table.pk, se); 638 } 639 } 640 641 private class Struct { 642 643 public int len; 644 public OID[] values; 645 public int size; 646 647 public OID prevRootOID; 648 public OID currentRootOID; 649 650 public OID prevStateOID; 651 public OID currentStateOID; 652 653 public void init() { 654 len = (int)(avgRowCount * FUDGE_FACTOR); 655 if (len < MIN_LEN) len = 0; 656 values = len == 0 ? null : new OID[len]; 657 if (Debug.DEBUG) { 658 if (((fetchCount + 1) % 10) == 0) { 659 System.out.println("JdbcFkCollectionField.fetch" + 660 " avgRowCount = " + avgRowCount + " " + 661 " len = " + len + " " + 662 " expansionCount = " + expansionCount + " " + 663 " fetchCount = " + fetchCount); 664 } 665 } 666 size = 0; 667 } 668 669 private void add(OID value) { 670 if (size == len) { 672 if (len == 0) { 673 values = new OID[len = MIN_LEN]; 674 } else { 675 len = len * 3 / 2 + 1; 676 OID[] a = new OID[len]; 677 System.arraycopy(values, 0, a, 0, size); 678 values = a; 679 expansionCount++; 680 } 681 } 682 values[size++] = value; 683 } 684 685 688 public void trim() { 689 if (values.length == size) return; 690 OID[] a = new OID[size]; 691 System.arraycopy(values, 0, a, 0, size); 692 values = a; 693 } 694 } 695 696 700 private void updateStatistics(int size) { 701 int fc = ++fetchCount; 702 if (fc > WINDOW_SIZE) { 703 fc = WINDOW_SIZE; 704 } else if (fc == 1) { 705 avgRowCount = size; 706 } else if (fc < 0) { 707 fc = fetchCount = WINDOW_SIZE; 708 } else { 709 avgRowCount = (avgRowCount * (fc - 1) + size) / fc; 710 } 711 } 712 713 717 private SelectExp getSelectExp(FetchGroupField field, 718 JdbcStorageManager sm, FgDs[] fgDses) { 719 SelectExp root = new SelectExp(); 720 root.table = elementJdbcClass.table; 721 root.selectList = JdbcColumn.toSqlExp(root.table.pk, root); 722 723 if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO) { 724 sm.addSelectFetchGroup(root, field.nextFetchGroup, 725 true, 726 fgDses[0] = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, false), 727 root, root.table.pk, this); 728 } 729 730 SelectExp se = root.findTable(ourPkColumns[0].table); 733 if (se == null) { 734 se = new SelectExp(); 735 se.table = ourPkColumns[0].table; 736 root.addJoin(root.table.pk, se.table.pk, se); 737 } 738 739 root.whereExp = JdbcColumn.createEqualsParamExp(ourPkColumns, se); 741 if (((JdbcClass)fmd.elementTypeMetaData.storeClass).classIdCol != null) { 742 root.whereExp.next = ((JdbcClass)fmd.elementTypeMetaData.storeClass).getCheckClassIdExp( 743 root); 744 AndExp andExp = new AndExp(root.whereExp); 745 root.whereExp = andExp; 746 } 747 748 if (fmd.ordering != null) { 750 root.addOrderBy(fmd.ordering, false); 751 } 752 753 if (Debug.DEBUG) { 754 System.out.println("%%% JdbcFKCollectionField.getSelectExp: " + 755 fmd.getQName()); 756 root.dump(" "); 757 System.out.println("%%%"); 758 } 759 760 return root; 761 } 762 763 767 public SelectExp getSelectExpFrom(JdbcStorageManager sm, SelectExp joinToExp, 768 FetchGroupField field, FgDs owningFgDs) { 769 SelectExp root = new SelectExp(); 770 root.outer = true; 771 root.table = elementJdbcClass.table; 772 root.selectList = JdbcColumn.toSqlExp(ourPkColumns, root, 773 JdbcColumn.toSqlExp(root.table.pk, root)); 774 775 if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO) { 776 FgDs fgDs = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, true); 777 sm.addSelectFetchGroup(root, field.nextFetchGroup, 778 true, fgDs, root, root.table.pk, this); 779 owningFgDs.valueJs = fgDs.getJoinStruct(); 780 } 781 782 if (fmd.ordering != null) { 784 root.addOrderBy(fmd.ordering, false); 785 } 786 787 if (Debug.DEBUG) { 788 System.out.println("%%% JdbcFKCollectionField.getSelectExp: " + 789 fmd.getQName()); 790 root.dump(" "); 791 System.out.println("%%%"); 792 } 793 794 795 joinToExp.addJoin(joinToExp.table.pk, ourPkColumns, root); 796 joinToExp.appendOrderByExp(root.orderByList); 797 root.orderByList = null; 798 return root; 799 } 800 801 public SelectExp getSelectFilterExp(JdbcStorageManager sm, FetchGroupField field, 802 ColFieldHolder colFHolder) { 803 SelectExp root = new SelectExp(); 804 root.table = elementJdbcClass.table; 805 root.selectList = JdbcColumn.toSqlExp(root.table.pk, root); 806 807 root.whereExp = ((JdbcClass)fmd.elementTypeMetaData.storeClass).getCheckClassIdExp( 808 root); 809 810 SqlExp e = JdbcColumn.toSqlExp(ourPkColumns, root, root.selectList); 812 root.selectList = e; 813 root.appendOrderByForColumns(ourPkColumns); 814 815 if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO) { 816 FgDs fgDs = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs( 817 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER); 818 colFHolder.valueJs = fgDs.getJoinStruct(); 819 sm.addSelectFetchGroup(root, field.nextFetchGroup, true, fgDs, 820 false); 821 } 822 823 if (fmd.ordering != null) { 825 root.addOrderBy(fmd.ordering, true); 826 } 827 828 return root; 829 } 830 831 public SelectExp getSelectFilterJoinExp(boolean value, SelectExp lhSe, 832 SelectExp rootSe, boolean addRootJoin) { 833 SelectExp root = new SelectExp(); 834 root.table = elementJdbcClass.table; 835 lhSe.addJoin(lhSe.table.pk, ourPkColumns, root); 836 return root; 837 } 838 839 842 public SqlExp toIsEmptySqlExp(JdbcJDOQLCompiler comp, SelectExp root) { 843 SelectExp se = new SelectExp(); 844 se.table = elementJdbcClass.table; 845 se.jdbcField = this; 846 se.subSelectJoinExp = root.createJoinExp(root.table.pk, ourPkColumns, 847 se); 848 return new UnaryOpExp(new ExistsExp(se, true), UnaryOpExp.OP_NOT); 850 } 851 852 855 public SqlExp toContainsSqlExp(JdbcJDOQLCompiler comp, SelectExp root, 856 Node args) { 857 if (args instanceof VarNodeIF) { 858 VarNode v = ((VarNodeIF)args).getVarNode(); 859 SelectExp vse = (SelectExp)v.getStoreExtent(); 860 861 if (vse.table == ourPkColumns[0].table) { 863 vse.subSelectJoinExp = root.createJoinExp(root.table.pk, 864 ourPkColumns, vse); 865 } else { 866 SelectExp se = new SelectExp(); 867 se.table = ourPkColumns[0].table; 868 se.outer = vse.outer; 869 vse.addJoin(vse.table.pk, ourPkColumns[0].table.pk, se); 870 } 871 872 if (v.getCmd() != fmd.elementTypeMetaData) { 873 vse.whereExp = SelectExp.appendWithAnd(vse.whereExp, 875 ((JdbcClass)fmd.elementTypeMetaData.storeClass).getCheckClassIdExp( 876 vse)); 877 } 878 879 return new ExistsExp(vse, true, v); 880 } else { 881 SelectExp se = new SelectExp(); 882 se.table = elementJdbcClass.table; 883 se.jdbcField = this; 884 se.subSelectJoinExp = root.createJoinExp(root.table.pk, 885 ourPkColumns, se); 886 SqlExp left = JdbcColumn.toSqlExp(se.table.pkSimpleCols, se); 887 for (SqlExp e = left; e != null; e = e.next) { 888 ((ColumnExp)e).cmd = fmd.elementTypeMetaData; 889 } 890 SqlExp right = comp.getVisitor().toSqlExp(args, root, left, 0, null); 891 if (left.next == null && right.next == null) { 892 BinaryOpExp ans = new BinaryOpExp(left, BinaryOpExp.EQUAL, 893 right); 894 if (right instanceof ParamExp) { 895 ParamExp p = (ParamExp)right; 896 p.usage.expList = ans; 897 p.usage.expCount = 1; 898 } 899 se.whereExp = ans; 900 } else { 901 throw BindingSupportImpl.getInstance().internal( 902 "not implemented"); 903 } 904 return new ExistsExp(se, false); 905 } 906 } 907 908 } 909 | Popular Tags |