1 2 12 package com.versant.core.jdbc.metadata; 13 14 import com.versant.core.jdbc.sql.JdbcNameGenerator; 15 import com.versant.core.jdbc.sql.exp.*; 16 import com.versant.core.jdbc.*; 17 import com.versant.core.jdbc.query.JdbcJDOQLCompiler; 18 import com.versant.core.server.*; 19 import com.versant.core.metadata.parser.JdoElement; 20 import com.versant.core.metadata.parser.JdoExtension; 21 import com.versant.core.metadata.parser.JdoExtensionKeys; 22 import com.versant.core.metadata.*; 23 import com.versant.core.common.OID; 24 import com.versant.core.common.State; 25 import com.versant.core.common.Utils; 26 import com.versant.core.util.CharBuf; 27 import com.versant.core.common.*; 28 import com.versant.core.jdo.query.Node; 29 import com.versant.core.jdo.query.OrderNode; 30 import com.versant.core.common.Debug; 31 32 import java.io.PrintStream ; 33 import java.util.ArrayList ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.sql.*; 37 38 import com.versant.core.common.BindingSupportImpl; 39 40 43 public class JdbcMapField extends JdbcLinkCollectionField { 44 45 private static final Object [] EMPTY_OBJECT_ARRAY = new Object [0]; 46 private static final OID[] EMPTY_OID_ARRAY = new OID[0]; 47 48 52 public JdbcColumn keyColumns[]; 53 59 public boolean keysDependent; 60 63 public boolean keysAreOIDs; 64 68 public int useKeyJoin; 69 70 private transient boolean createKeyConstraint; 71 private transient String keyConstraintName; 72 73 public void dump(PrintStream out, String indent) { 74 super.dump(out, indent); 75 String is = indent + " "; 76 if (keyColumns == null) { 77 out.println(is + "keyColumns null"); 78 } else { 79 for (int i = 0; i < keyColumns.length; i++) { 80 out.println(is + "keyColumns[" + i + "] " + keyColumns[i]); 81 } 82 } 83 out.println(is + "keysDependent " + keysDependent); 84 out.println(is + "keysAreOIDs " + keysAreOIDs); 85 out.println(is + "useKeyJoin " + toUseJoinString(useKeyJoin)); 86 } 87 88 91 public int getUseKeyJoin() { 92 return useKeyJoin; 93 } 94 95 99 public void processMetaData(JdoElement context, JdbcMetaDataBuilder mdb, 100 boolean quiet) { 101 keysAreOIDs = fmd.keyTypeMetaData != null; 102 if (keysAreOIDs) { 103 useKeyJoin = JdbcField.USE_JOIN_INNER; 104 } else { 105 useKeyJoin = JdbcField.USE_JOIN_NO; 106 } 107 super.processMetaData(context, mdb, quiet); 108 } 109 110 113 protected void createLinkTablePK() { 114 linkTable.setPk(JdbcColumn.concat(ourPkColumns, keyColumns)); 115 } 116 117 120 protected void completeKeyAndValueColumnMetaData(JdbcClass jdbcClass, 121 ArrayList cols, 122 JdoElement context, JdoExtension[] linkNested, 123 JdbcMetaDataBuilder mdb, boolean quiet) { 124 125 JdoExtension ext = JdoExtension.find(JdoExtensionKeys.JDBC_KEY, 127 linkNested); 128 if (fmd.keyTypeMetaData != null) { JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder( 130 fmd.classMetaData, 131 mdb, fmd.keyTypeMetaData, context, 132 JdbcMetaDataBuilder.KEY_FIELDNAME, 133 ext == null ? null : ext.nested, quiet); 134 keyColumns = rdb.getCols(); 135 cols.addAll(rdb.getColsList()); 136 createKeyConstraint = !rdb.isDoNotCreateConstraint(); 137 keyConstraintName = rdb.getConstraintName(); 138 } else { 139 if (fmd.keyType == Object .class) { 140 throw BindingSupportImpl.getInstance().runtime("You must specify the key-type for maps\n" + 141 fmd + "\n" + context.getContext()); 142 } 143 JdbcColumn kc = mdb.createColumn(ext == null ? null : ext.nested, 144 JdbcMetaDataBuilder.KEY_FIELDNAME, fmd.keyType); 145 keyColumns = new JdbcColumn[]{kc}; 146 cols.add(kc); 147 } 148 149 int n = keyColumns.length; 150 for (int i = 0; i < n; i++) keyColumns[i].setNulls(false); 151 152 super.completeKeyAndValueColumnMetaData(jdbcClass, cols, context, 153 linkNested, mdb, quiet); 154 } 155 156 159 protected void nameKeyAndValueColumns(JdbcNameGenerator namegen, 160 String linkTableNameForNamegen) { 161 if (keysAreOIDs) { 163 String [] keyPkNames = JdbcColumn.getColumnNames( 164 ((JdbcClass)fmd.keyTypeMetaData.storeClass).table.pk); 165 String [] linkKeyRefNames = JdbcColumn.getColumnNames(keyColumns); 166 namegen.generateLinkTableValueRefNames(linkTable.name, 167 keyPkNames, fmd.keyType.getName(), linkKeyRefNames, true); 168 JdbcColumn.setColumnNames(keyColumns, linkKeyRefNames); 169 } else { 170 JdbcColumn c = keyColumns[0]; 171 if (c.name == null) { 172 c.name = namegen.generateLinkTableValueName(linkTable.name, 173 fmd.keyType, true); 174 } 175 } 176 177 super.nameKeyAndValueColumns(namegen, linkTableNameForNamegen); 178 } 179 180 183 protected void nameLinkTable(JdbcNameGenerator namegen, 184 JdbcClass jdbcClass) { 185 linkTable.name = namegen.generateLinkTableName(jdbcClass.table.name, 186 fmd.name, null); 187 } 188 189 192 protected List createConstraints(boolean pkConstraint, 193 String pkConstraintName) { 194 List constraints = super.createConstraints(pkConstraint, 195 pkConstraintName); 196 197 if (createKeyConstraint && keysAreOIDs 198 && fmd.keyTypeMetaData.storeClass != null) { 199 JdbcConstraint keyCon = new JdbcConstraint(); 200 keyCon.src = linkTable; 201 keyCon.srcCols = keyColumns; 202 keyCon.dest = ((JdbcClass)fmd.keyTypeMetaData.storeClass).table; 203 keyCon.name = keyConstraintName; 204 constraints.add(keyCon); 205 } 206 207 return constraints; 208 } 209 210 214 public void persistPass2Block(PersistGraph graph, int blockStart, 215 int blockEnd, CharBuf s, Connection con, boolean batchInserts, 216 boolean batchUpdates) throws SQLException { 217 PreparedStatement psdel = null; 218 PreparedStatement psdelAll = null; 219 PreparedStatement psins = null; 220 int delCount = 0; 221 try { 222 String psdelSql = null; 223 String psdelAllSql = null; 224 String psinsSql = null; 225 for (int pos = blockStart; pos < blockEnd; pos++) { 226 State ns = graph.getNewState(pos); 227 if (!ns.containsField(stateFieldNo)) continue; 228 229 MapDiff diff = (MapDiff)ns.getInternalObjectField(stateFieldNo); 230 231 OID oid = graph.getOID(pos); 232 233 if (diff == null || diff.status == CollectionDiff.STATUS_NEW) { 234 if (!oid.isNew()) { 235 if (psdelAll == null) { 236 psdelAllSql = getDeleteAllLinkTableRowsSql(s); 237 psdelAll = con.prepareStatement(psdelAllSql); 238 } 239 ((JdbcOID)oid).setParams(psdelAll, 1); 240 if (batchUpdates) { 241 psdelAll.addBatch(); 242 } else { 243 try { 244 psdelAll.execute(); 245 } catch (Exception e) { 246 throw mapException(e, 247 "Delete all link table rows failed: " + 248 JdbcUtils.toString(e) + "\n" + 249 "Field: " + fmd.getQName() + "\n" + 250 "Instance: " + oid.toSString() + "\n" + 251 JdbcUtils.getPreparedStatementInfo( 252 psdelAllSql, psdelAll)); 253 } 254 } 255 } 256 } else { 257 Object [] deleted = diff.deletedKeys; 258 if (deleted != null && deleted.length > 0) { 259 if (psdel == null) { 260 psdelSql = getDeleteLinkTableRowSql(s); 261 psdel = con.prepareStatement(psdelSql); 262 } 263 deleteMapLinkTableRows(oid, deleted, psdel, 264 batchUpdates, psdelSql); 265 delCount += deleted.length; 266 } 267 } 268 269 if (diff != null) { 270 Object [] inserted = diff.insertedKeys; 271 if (inserted != null && inserted.length > 0) { 272 if (psins == null) { 273 psinsSql = getInsertLinkTableRowSql(s); 274 psins = con.prepareStatement(psinsSql); 275 } 276 insertMapLinkTableRows(oid, inserted, diff.insertedValues, 277 psins, batchInserts, psinsSql); 278 } 279 } 280 } 281 282 if (batchUpdates) { 283 execLinkTableBatchDeletes(delCount, psdel, psdelSql, 284 psdelAll, psdelAllSql); 285 } 286 if (batchInserts && psins != null) { 287 execLinkTableBatchInserts(psins, psinsSql); 288 } 289 } finally { 290 cleanup(psdel); 291 cleanup(psdelAll); 292 cleanup(psins); 293 } 294 } 295 296 299 private void deleteMapLinkTableRows(OID oid, Object [] deleted, 300 PreparedStatement psdel, boolean batch, String sql) 301 throws SQLException { 302 if (keysAreOIDs) { 303 for (int j = deleted.length - 1; j >= 0; j--) { 304 int pp = ((JdbcOID)oid).setParams(psdel, 1); 305 ((JdbcOID)deleted[j]).setParams(psdel, pp); 306 if (batch) { 307 psdel.addBatch(); 308 } else { 309 int uc; 310 try { 311 uc = psdel.executeUpdate(); 312 } catch (Exception e) { 313 throw mapException(e, 314 "Delete map link table row failed: " + 315 JdbcUtils.toString(e) + "\n" + 316 "Field: " + fmd.getTypeQName() + "\n" + 317 "Key: " + ((OID)deleted[j]).toSString() + "\n" + 318 "Instance: " + oid.toSString() + "\n" + 319 JdbcUtils.getPreparedStatementInfo(sql, psdel)); 320 } 321 if (uc == 0) { 322 throw BindingSupportImpl.getInstance().concurrentUpdate("Map link table row not found: " + 323 "Field: " + fmd.getTypeQName() + "\n" + 324 "Key: " + ((OID)deleted[j]).toSString() + "\n" + 325 "Instance: " + oid.toSString() + "\n" + 326 JdbcUtils.getPreparedStatementInfo(sql, psdel), deleted[j]); 327 } 328 } 329 } 330 } else { 331 JdbcColumn kc = keyColumns[0]; 332 for (int j = deleted.length - 1; j >= 0; j--) { 333 int pp = ((JdbcOID)oid).setParams(psdel, 1); 334 kc.set(psdel, pp, deleted[j]); 335 if (batch) { 336 psdel.addBatch(); 337 } else { 338 int uc; 339 try { 340 uc = psdel.executeUpdate(); 341 } catch (Exception e) { 342 throw mapException(e, 343 "Delete map link table row failed: " + 344 JdbcUtils.toString(e) + "\n" + 345 "Field: " + fmd.getTypeQName() + "\n" + 346 "Key: " + Utils.toString(deleted[j]) + "\n" + 347 "Instance: " + oid.toSString() + "\n" + 348 JdbcUtils.getPreparedStatementInfo(sql, psdel)); 349 } 350 if (uc == 0) { 351 throw BindingSupportImpl.getInstance().concurrentUpdate("Map link table row not found: " + 352 "Field: " + fmd.getTypeQName() + "\n" + 353 "Key: " + Utils.toString(deleted[j]) + "\n" + 354 "Instance: " + oid.toSString() + "\n" + 355 JdbcUtils.getPreparedStatementInfo(sql, psdel), oid); 356 } 357 } 358 } 359 } 360 } 361 362 365 private void insertMapLinkTableRows(OID oid, Object [] insertedKeys, 366 Object [] insertedValues, PreparedStatement psins, 367 boolean batch, String sql) 368 throws SQLException { 369 370 JdbcColumn kc = keyColumns[0]; 371 JdbcColumn vc = valueColumns[0]; 372 373 int ilen = insertedKeys.length; 375 for (int j = 0; j < ilen; j++) { 376 int pp = ((JdbcOID)oid).setParams(psins, 1); 377 378 if (keysAreOIDs) { 380 pp = ((JdbcOID)insertedKeys[j]).setParams(psins, pp); 381 } else { 382 kc.set(psins, pp++, insertedKeys[j]); 383 } 384 385 if (valuesAreOIDs) { 387 if (insertedValues[j] == null) { 388 JdbcGenericOID.setNullParams(psins, pp, fmd.elementTypeMetaData); 389 } else { 390 ((JdbcOID)insertedValues[j]).setParams(psins, pp); 391 } 392 } else { 393 vc.set(psins, pp, insertedValues[j]); 394 } 395 396 if (batch) { 397 psins.addBatch(); 398 } else { 399 try { 400 psins.execute(); 401 } catch (Exception e) { 402 String keyStr = keysAreOIDs 403 ? ((OID)insertedKeys[j]).toSString() 404 : Utils.toString(insertedKeys[j]); 405 String valueStr = valuesAreOIDs 406 ? ((OID)insertedValues[j]).toSString() 407 : Utils.toString(insertedValues[j]); 408 throw mapException(e, 409 "Insert link table row failed: " + 410 JdbcUtils.toString(e) + "\n" + 411 "Field: " + fmd.getQName() + "\n" + 412 "Instance: " + oid.toSString() + "\n" + 413 "Key: " + keyStr + "\n" + 414 "Value: " + valueStr + "\n" + 415 JdbcUtils.getPreparedStatementInfo(sql, psins)); 416 } 417 } 418 } 419 } 420 421 425 public SelectExp getSelectExp(JdbcStorageManager dataStore, FetchGroupField field, 426 FgDs[] fgDses) { 427 SelectExp root = super.getSelectExp(dataStore, field, fgDses); 428 429 SqlExp e = JdbcColumn.toSqlExp(keyColumns, root, root.selectList); 431 root.selectList = e; 432 433 if (keysAreOIDs) { 435 if (field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO) { 436 SelectExp se = new SelectExp(); 437 JdbcClass keyJdbcClass = (JdbcClass)fmd.keyTypeMetaData.storeClass; 438 se.table = keyJdbcClass.table; 439 se.outer = field.jdbcUseKeyJoin == JdbcField.USE_JOIN_OUTER; 440 dataStore.addSelectFetchGroup(se, field.nextKeyFetchGroup, true, 441 fgDses[1] = ((JdbcFetchGroup)field.nextKeyFetchGroup.storeFetchGroup).getFgDs( 442 true, se.outer), 443 false); 444 root.addJoin(keyColumns, se.table.pk, se); 445 } 446 } 447 return root; 448 } 449 450 public SelectExp getSelectFilterJoinExp(boolean value, SelectExp lhSe, 451 SelectExp rootSe, boolean addRootJoin) { 452 SelectExp root = new SelectExp(); 453 root.table = linkTable; 454 455 SelectExp se = new SelectExp(); 456 if (value) { 457 se.table = ((JdbcClass)fmd.elementTypeMetaData.storeClass).table; 458 root.addJoin(valueColumns, se.table.pk, se); 459 } else { 460 se.table = ((JdbcClass)fmd.keyTypeMetaData.storeClass).table; 461 root.addJoin(keyColumns, se.table.pk, se); 462 } 463 464 lhSe.addJoin(lhSe.table.pk, ourPkColumns, root); 465 return se; 466 } 467 468 public SelectExp getSelectFilterExp(JdbcStorageManager sm, FetchGroupField field, 469 ColFieldHolder colFHolder) { 470 SelectExp root = new SelectExp(); 471 root.table = linkTable; 472 473 SqlExp e = JdbcColumn.toSqlExp(valueColumns, root); 475 root.selectList = e; 476 477 e = JdbcColumn.toSqlExp(keyColumns, root, root.selectList); 479 root.selectList = e; 480 481 e = JdbcColumn.toSqlExp(ourPkColumns, root, root.selectList); 483 root.selectList = e; 484 root.appendOrderByForColumns(ourPkColumns); 486 487 if (valuesAreOIDs) { 488 if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO || fmd.ordering != null) { 489 SelectExp se = new SelectExp(); 490 JdbcClass valueJdbcClass = (JdbcClass)fmd.elementTypeMetaData.storeClass; 491 se.table = valueJdbcClass.table; 492 se.outer = field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER; 493 FgDs fgDs = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, se.outer); 494 sm.addSelectFetchGroup(se, field.nextFetchGroup, true, 495 fgDs, false); 496 colFHolder.valueJs = fgDs.getJoinStruct(); 497 498 root.addJoin(valueColumns, se.table.pk, se); 499 500 if (fmd.ordering != null) { 501 se.addOrderBy(fmd.ordering, false); 502 root.appendOrderByExp(se.orderByList); 503 se.orderByList = null; 504 } 505 } 506 } else { 507 if (fmd.ordering != null) { 508 boolean desc = fmd.ordering[0].order == OrderNode.ORDER_DESCENDING; 510 root.appendOrderByExp(new OrderExp( 511 valueColumns[0].toSqlExp(root), 512 desc)); 513 } 516 } 517 518 if (fmd.ordered) { 519 if (fmd.ordering != null) { 520 throw BindingSupportImpl.getInstance().internal( 521 "ordered == true && ordering != null, " + fmd.getTypeQName()); 522 } 523 root.appendOrderByForColumns(linkTable.pkSimpleCols); 524 } 525 526 if (keysAreOIDs) { 528 if (field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO) { 529 SelectExp se = new SelectExp(); 530 JdbcClass keyJdbcClass = (JdbcClass)fmd.keyTypeMetaData.storeClass; 531 se.table = keyJdbcClass.table; 532 se.outer = field.jdbcUseKeyJoin == JdbcField.USE_JOIN_OUTER; 533 534 FgDs fgDs = ((JdbcFetchGroup)field.nextKeyFetchGroup.storeFetchGroup).getFgDs(true, se.outer); 535 sm.addSelectFetchGroup(se, field.nextKeyFetchGroup, true, 536 fgDs, false); 537 colFHolder.keyJs = fgDs.getJoinStruct(); 538 root.addJoin(keyColumns, se.table.pk, se); 539 } 540 } 541 return root; 542 } 543 544 public int fetchFrom(ResultSet rs, OID oid, 545 State state, FetchGroupField field, boolean forUpdate, 546 StateContainer container, 547 boolean fetchPass2Fields, int colIndex, 548 FetchInfo fetchInfo, JdbcStorageManager sm) throws SQLException { 549 ArrayList keys = new ArrayList (); 550 ArrayList values = new ArrayList (); 551 552 ClassMetaData keyCmd = fmd.keyTypeMetaData; 554 boolean keyJoined = field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO; 555 FetchGroup keyNFG = field.nextKeyFetchGroup; 556 JdbcColumn kc = keyColumns[0]; 557 int keyScc = keyColumns.length; 558 OID keyOid = null; 559 560 ClassMetaData valueCmd = fmd.elementTypeMetaData; 562 boolean valueJoined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO; 563 FetchGroup nfg = field.nextFetchGroup; 564 JdbcColumn vc = valueColumns[0]; 565 int valueScc = valueColumns.length; 566 567 MutableInt nextIndex = null; 568 if (valuesAreOIDs) nextIndex = new MutableInt(); 569 boolean first = true; 570 for (; ;) { 571 if (first) { 572 first = false; 573 } else { 574 if (!rs.next()) break; 575 } 576 577 OID owningOid = fmd.classMetaData.createOID(false); 578 if (!((JdbcOID)owningOid).copyKeyFields(rs, colIndex)) { 579 break; 581 } 582 int index = colIndex + ourPkColumns.length; 583 584 if (keysAreOIDs) { 585 keyOid = keyCmd.createOID(false); 586 boolean isNull = !((JdbcOID)keyOid).copyKeyFields(rs, colIndex); 587 if (!isNull) keys.add(keyOid); 588 } else { 589 keys.add(kc.get(rs, colIndex )); 590 } 591 index += keyScc; 592 593 if (valuesAreOIDs) { 594 OID valueOid = valueCmd.createOID(false); 595 boolean isNull = !((JdbcOID)valueOid).copyKeyFields(rs, index); 596 index += valueScc; 597 if (!isNull) values.add(valueOid); 598 599 if (!isNull && valueJoined) { 600 if (container.isStateRequired(valueOid, nfg)) { 601 State valueState = sm.createStateImp(rs, valueOid, 602 field.nextFetchGroup, forUpdate, index, nextIndex, 603 true, container, 604 ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, true), 605 fetchPass2Fields, false, null); 606 index = nextIndex.value; 607 container.addState(valueOid, valueState); 608 } else { 609 index = sm.skipState(index, 610 ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, true)); 611 } 612 } 613 } else { 614 values.add(vc.get(rs, index )); 615 index += valueScc; 616 } 617 618 if (keysAreOIDs && keyJoined 619 && container.isStateRequired(keyOid, keyNFG)) { 620 State keyState = sm.createStateImp(rs, keyOid, 621 field.nextKeyFetchGroup, forUpdate, index, null, 622 true, container, 623 ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, true), 624 fetchPass2Fields, false, null); 625 container.addState(keyOid, keyState); 626 } 627 } 628 629 MapEntries me = new MapEntries(); 630 if (keysAreOIDs) { 631 me.keys = new OID[keys.size()]; 632 keys.toArray(me.keys); 633 } else { 634 me.keys = keys.toArray(); 635 } 636 if (valuesAreOIDs) { 637 me.values = new OID[values.size()]; 638 values.toArray(me.values); 639 } else { 640 me.values = values.toArray(); 641 } 642 state.setInternalObjectField(fmd.stateFieldNo, me); 643 return keys.size(); 644 } 645 646 public SelectExp getSelectExpFrom(JdbcStorageManager sm, 647 SelectExp joinToExp, FetchGroupField field, 648 FgDs owningFgDs) { 649 SelectExp root = super.getSelectExpFromImp(joinToExp, field, sm, owningFgDs); 650 root.selectList = JdbcColumn.toSqlExp(keyColumns, root, root.selectList); 651 root.selectList = JdbcColumn.toSqlExp(ourPkColumns, root, root.selectList); 652 653 if (keysAreOIDs) { 655 if (field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO) { 656 SelectExp se = new SelectExp(); 657 JdbcClass keyJdbcClass = (JdbcClass)fmd.keyTypeMetaData.storeClass; 658 se.table = keyJdbcClass.table; 659 se.outer = true; 660 FgDs fgDs = ((JdbcFetchGroup)field.nextKeyFetchGroup.storeFetchGroup).getFgDs(true, se.outer); 661 sm.addSelectFetchGroup(se, field.nextKeyFetchGroup, true, 662 fgDs, false); 663 owningFgDs.keyJs = fgDs.getJoinStruct(); 664 root.addJoin(keyColumns, se.table.pk, se); 665 } 666 } 667 return root; 668 } 669 670 673 public int fetch(JdbcStorageManager sm, OID oid, State state, 674 FetchGroupField field, boolean forUpdate, 675 StateContainer container, boolean fetchPass2Fields, 676 ColFieldHolder colFHolder) 677 throws SQLException { 678 JoinStructure valueJs = null; 679 JoinStructure keyJs = null; 680 681 FgDs[] fgDses = new FgDs[2]; 682 683 String sql = forUpdate ? field.jdbcSelectSqlForUpdate : field.jdbcSelectSql; 684 if (sql == null) { 685 SelectExp se = getSelectExp(sm, field, fgDses); 686 CharBuf s = sm.generateSql(se); 687 sql = s.toString(); 688 if (forUpdate) { 689 field.jdbcSelectSqlForUpdate = sql; 690 } else { 691 field.jdbcSelectSql = sql; 692 } 693 } 694 695 if (valuesAreOIDs) { 696 fgDses[0] = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getExistingFgDs( 697 true, field.jdbcUseJoin != JdbcField.USE_JOIN_INNER); 698 if (colFHolder != null) { 699 if (fgDses[0] != null) { 700 colFHolder.valueJs = fgDses[0].getJoinStruct(); 701 } 702 } 703 } 704 if (keysAreOIDs) { 705 fgDses[1] = ((JdbcFetchGroup)field.nextKeyFetchGroup.storeFetchGroup).getExistingFgDs( 706 true, field.jdbcUseKeyJoin == JdbcField.USE_JOIN_OUTER); 707 if (colFHolder != null) { 708 if (fgDses[1] != null) { 709 colFHolder.keyJs = fgDses[1].getJoinStruct(); 710 } 711 } 712 } 713 714 PreparedStatement ps = null; 715 ResultSet rs = null; 716 try { 717 ps = sm.con().prepareStatement(sql); 718 719 ArrayList keys = new ArrayList (); 720 ArrayList values = new ArrayList (); 721 722 final boolean keyJoined = field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO; 724 int keyScc = keyColumns.length; 725 OID keyOid = null; 726 727 final boolean valueJoined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO 729 || fmd.ordering != null; 730 final int valueScc = valueColumns.length; 731 732 ((JdbcOID)oid).setParams(ps, 1); 734 try { 735 rs = ps.executeQuery(); 736 } catch (Exception e) { 737 throw mapException(e, 738 "Fetch link table rows failed: " + 739 JdbcUtils.toString(e) + "\n" + 740 "Field: " + fmd.getTypeQName() + "\n" + 741 "Instance: " + oid.toSString() + "\n" + 742 JdbcUtils.getPreparedStatementInfo(sql, ps)); 743 } 744 745 MutableInt nextIndex = null; 746 if (valuesAreOIDs) nextIndex = new MutableInt(); 747 for (; rs.next();) { 748 749 if (keysAreOIDs) { 750 keyOid = fmd.keyTypeMetaData.createOID(false); 751 ((JdbcOID)keyOid).copyKeyFields(rs, 1); 752 keys.add(keyOid); 753 } else { 754 keys.add(keyColumns[0].get(rs, 1 )); 755 } 756 int index = 1 + keyScc; 757 758 if (valuesAreOIDs) { 759 OID valueOid = fmd.elementTypeMetaData.createOID(false); 760 if (((JdbcOID)valueOid).copyKeyFields(rs, index)) { 761 values.add(valueOid); 762 index += valueScc; 763 if (valueJoined) { 764 if (container.isStateRequired(valueOid, field.nextFetchGroup)) { 765 container.addState(valueOid, 766 sm.createStateImp(rs, valueOid, 767 field.nextFetchGroup, forUpdate, index, nextIndex, 768 true, container, 769 fgDses[0], 770 fetchPass2Fields, false, valueJs)); 771 index = nextIndex.value; 772 } else { 773 index = sm.skipState(index, fgDses[0]); 774 } 775 } 776 } else { 777 index += valueScc; 778 values.add(null); 779 } 780 } else { 781 values.add( 782 valueColumns[0].get(rs, index )); 783 index += valueScc; 784 } 785 786 if (keysAreOIDs && keyJoined 787 && container.isStateRequired(keyOid, field.nextKeyFetchGroup)) { 788 container.addState(keyOid, sm.createStateImp(rs, keyOid, 789 field.nextKeyFetchGroup, forUpdate, index, null, 790 true, container, 791 fgDses[1], 792 fetchPass2Fields, false, keyJs)); 793 } 794 } 795 796 MapEntries me = new MapEntries(); 797 if (keysAreOIDs) { 798 me.keys = new OID[keys.size()]; 799 keys.toArray(me.keys); 800 } else { 801 me.keys = keys.toArray(); 802 } 803 if (valuesAreOIDs) { 804 me.values = new OID[values.size()]; 805 values.toArray(me.values); 806 } else { 807 me.values = values.toArray(); 808 } 809 state.setInternalObjectField(fmd.stateFieldNo, me); 810 812 return keys.size(); 813 } finally { 814 cleanup(rs); 815 cleanup(ps); 816 } 817 } 818 819 822 public int fetchWithFilter(JdbcStorageManager sm, StateContainer oidStates, 823 FetchGroupField field, ResultSet rs, boolean forUpdate, 824 OID oidToCheckOn, 825 OID[] lastReadStateOID, ClassMetaData cmd, 826 ColFieldHolder colFHolder) throws SQLException { 827 828 ClassMetaData keyCmd = fmd.keyTypeMetaData; 829 boolean keyJoined = field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO; 830 FetchGroup keyNFG = field.nextKeyFetchGroup; 831 JdbcColumn kc = keyColumns[0]; 832 int keyScc = keyColumns.length; 833 834 ClassMetaData valueCmd = fmd.elementTypeMetaData; 836 boolean valueJoined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO; 837 FetchGroup nfg = field.nextFetchGroup; 838 JdbcColumn vc = valueColumns[0]; 839 int valueScc = valueColumns.length; 840 841 int rootOIDLength = ((JdbcClass)cmd.storeClass).table.pkSimpleColumnCount; 842 int stateOIDPKLen = ((JdbcClass)fmd.classMetaData.storeClass).table.pkSimpleColumnCount; 843 844 OID rootOid = cmd.createOID(false); 846 OID prevRootOid = cmd.createOID(false); 848 OID tmpOID = null; 849 850 OID stateOID = fmd.classMetaData.createOID(false); 851 OID prevStateOID = fmd.classMetaData.createOID(false); 852 OID tmpStateOID = null; 853 854 boolean currentRowValid = false; 855 boolean prevRowValid = false; 856 857 final ArrayList keys = new ArrayList (); 858 final ArrayList values = new ArrayList (); 859 860 MutableInt nextIndex = null; 861 if (valuesAreOIDs) nextIndex = new MutableInt(); 862 int returnState = 0; 863 864 FgDs fgDsValue = null; 865 if (valuesAreOIDs) { 866 fgDsValue = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getExistingFgDs( 867 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER); 868 if (colFHolder != null) { 869 colFHolder.valueJs = fgDsValue.getJoinStruct(); 870 } 871 } 872 873 FgDs fgDsKeys = null; 874 if (keysAreOIDs) { 875 fgDsKeys = ((JdbcFetchGroup)field.nextKeyFetchGroup.storeFetchGroup).getFgDs( 876 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER); 877 if (colFHolder != null) { 878 colFHolder.keyJs = fgDsKeys.getJoinStruct(); 879 } 880 } 881 882 883 if (lastReadStateOID[0] != null) { 885 int index = 1 + rootOIDLength + stateOIDPKLen; 887 888 prevRootOid = lastReadStateOID[0]; 889 891 stateOID = lastReadStateOID[1]; 892 894 currentRowValid = oidStates.containsKey(stateOID); 895 if (currentRowValid) { 896 returnState |= STATUS_VALID_ROWS; 897 OID keyOid = null; 898 if (keysAreOIDs) { 899 keyOid = keyCmd.createOID(false); 900 ((JdbcOID)keyOid).copyKeyFields(rs, index); 901 keys.add(keyOid); 902 } else { 903 keys.add(kc.get(rs, index)); 904 } 905 index += keyScc; 906 907 if (valuesAreOIDs) { 908 OID valueOid = valueCmd.createOID(false); 909 ((JdbcOID)valueOid).copyKeyFields(rs, index); 910 index += valueScc; 911 values.add(valueOid); 912 if (valueJoined) { 913 if (oidStates.isStateRequired(valueOid, nfg)) { 914 State valueState = sm.createStateImp(rs, valueOid, 915 field.nextFetchGroup, forUpdate, index, nextIndex, 916 true, oidStates, 917 fgDsValue, 918 false, false, null); 919 920 index = nextIndex.value; 921 oidStates.addState(valueOid, valueState); 923 } else { 924 index = sm.skipState(index, fgDsValue); 925 } 926 } 927 } else { 928 values.add(vc.get(rs, index)); 929 index += valueScc; 930 } 931 932 if (keysAreOIDs && keyJoined 933 && oidStates.isStateRequired(keyOid, keyNFG)) { 934 State keyState = sm.createStateImp(rs, keyOid, 935 field.nextKeyFetchGroup, forUpdate, index, nextIndex, 936 true, oidStates, 937 fgDsKeys, 938 false, false, colFHolder.keyJs); 939 oidStates.addState(keyOid, keyState); 940 } 941 if (nextIndex != null) nextIndex.value = 0; 942 } 943 944 tmpOID = rootOid; 946 rootOid = prevRootOid; 947 prevRootOid = tmpOID; 948 949 tmpStateOID = stateOID; 951 stateOID = prevStateOID; 952 prevStateOID = tmpStateOID; 953 954 prevRowValid = currentRowValid; 955 } 956 957 for (; rs.next();) { 958 int index = 1; 959 960 ((JdbcOID)rootOid).copyKeyFields(rs, index); 961 index += rootOIDLength; 962 963 ((JdbcOID)stateOID).copyKeyFields(rs, index); 964 index += stateOIDPKLen; 965 966 currentRowValid = oidStates.containsKey(stateOID); 967 968 if (!stateOID.equals(prevStateOID) && prevRowValid) { 969 if (Debug.DEBUG) { 970 if (oidStates.get(prevStateOID) == null) { 971 ((StatesReturned)oidStates).dump(); 972 throw new NullPointerException (prevStateOID.toSString() + 973 " oidStates " + oidStates); 974 } 975 } 976 if (updateStateFilter(keys, values, 977 oidStates.get(prevStateOID))) { 978 returnState |= STATUS_DATA_ADDED; 979 } 980 981 if (oidToCheckOn.equals(prevRootOid) && !oidToCheckOn.equals( 982 rootOid)) { 983 lastReadStateOID[0] = rootOid; 984 lastReadStateOID[1] = stateOID; 985 returnState |= STATUS_VALID_ROWS; 986 return returnState; 987 } 988 989 keys.clear(); 990 values.clear(); 991 } 992 993 if (currentRowValid) { 994 returnState |= STATUS_VALID_ROWS; 995 OID keyOid = null; 996 if (keysAreOIDs) { 997 keyOid = keyCmd.createOID(false); 998 ((JdbcOID)keyOid).copyKeyFields(rs, index); 999 keys.add(keyOid); 1000 } else { 1001 keys.add(kc.get(rs, index)); 1002 } 1003 index += keyScc; 1004 1005 if (valuesAreOIDs) { 1006 OID valueOid = valueCmd.createOID(false); 1007 ((JdbcOID)valueOid).copyKeyFields(rs, index); 1008 index += valueScc; 1009 values.add(valueOid); 1010 if (valueJoined) { 1011 if (oidStates.isStateRequired(valueOid, nfg)) { 1012 State valueState = sm.createStateImp(rs, valueOid, 1013 field.nextFetchGroup, forUpdate, index, nextIndex, 1014 true, oidStates, 1015 ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs( 1016 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER), 1017 false, false, null); 1018 1019 index = nextIndex.value; 1020 oidStates.addState(valueOid, valueState); 1021 } else { 1022 index = sm.skipState(index, 1023 ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs( 1024 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER)); 1025 } 1026 } 1027 } else { 1028 values.add(vc.get(rs, index)); 1029 index += valueScc; 1030 } 1031 1032 if (keysAreOIDs && keyJoined 1033 && oidStates.isStateRequired(keyOid, keyNFG)) { 1034 State keyState = sm.createStateImp(rs, keyOid, 1035 field.nextKeyFetchGroup, forUpdate, index, nextIndex, 1036 true, oidStates, 1037 ((JdbcFetchGroup)field.nextKeyFetchGroup.storeFetchGroup).getFgDs( 1038 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER), 1039 false, false, colFHolder.keyJs); 1040 oidStates.addState(keyOid, keyState); 1041 } 1042 1043 if (nextIndex != null) nextIndex.value = 0; 1044 } 1045 1046 tmpOID = rootOid; 1048 rootOid = prevRootOid; 1049 prevRootOid = tmpOID; 1050 1051 tmpStateOID = stateOID; 1053 stateOID = prevStateOID; 1054 prevStateOID = tmpStateOID; 1055 1056 prevRowValid = currentRowValid; 1057 } 1058 1059 rs.close(); 1060 returnState |= STATUS_CLOSED; 1061 if ((returnState & STATUS_VALID_ROWS) == STATUS_VALID_ROWS) { 1062 if (updateStateFilter(keys, values, oidStates.get(prevStateOID))) { 1063 returnState |= STATUS_DATA_ADDED; 1064 } 1065 } 1066 return returnState; 1067 } 1068 1069 public void fillStateWithEmpty(FetchGroupField field, State state) { 1070 if (!state.containsField(fmd.stateFieldNo)) { 1071 MapEntries me = new MapEntries(); 1072 me.preGenerated = true; 1073 if (keysAreOIDs) { 1074 me.keys = EMPTY_OID_ARRAY; 1075 } else { 1076 me.keys = EMPTY_OBJECT_ARRAY; 1077 } 1078 if (valuesAreOIDs) { 1079 me.values = EMPTY_OID_ARRAY; 1080 } else { 1081 me.values = EMPTY_OBJECT_ARRAY; 1082 } 1083 state.setInternalObjectField(fmd.stateFieldNo, me); 1084 } 1085 } 1086 1087 1091 private boolean updateStateFilter(ArrayList keys, ArrayList values, 1092 State state) { 1093 if (Debug.DEBUG) { 1094 if (!state.containsField(fmd.stateFieldNo)) { 1096 throw BindingSupportImpl.getInstance().internal("The mapField '" + fmd.name 1097 + "' is not filled"); 1098 } 1099 if (state.getInternalObjectField(fmd.stateFieldNo) == null) { 1100 throw BindingSupportImpl.getInstance().internal("The mapField '" + fmd.name 1101 + "' is filled with a null value"); 1102 } 1103 } 1105 1106 1110 if ((state.getInternalObjectField(fmd.stateFieldNo) instanceof Map )) { 1111 return false; 1117 } 1118 1119 if (!((MapEntries)state.getInternalObjectField(fmd.stateFieldNo)).preGenerated) { 1120 return false; 1121 } 1122 1123 MapEntries me = new MapEntries(); 1124 if (keysAreOIDs) { 1125 me.keys = new OID[keys.size()]; 1126 keys.toArray(me.keys); 1127 } else { 1128 me.keys = keys.toArray(); 1129 } 1130 if (valuesAreOIDs) { 1131 me.values = new OID[values.size()]; 1132 values.toArray(me.values); 1133 } else { 1134 me.values = values.toArray(); 1135 } 1136 state.setInternalObjectField(fmd.stateFieldNo, me); 1137 return true; 1138 } 1139 1140 1143 public SqlExp toContainsKeySqlExp(JdbcJDOQLCompiler comp, SelectExp root, 1144 Node args) { 1145 return toContainsSqlExp(keyColumns, fmd.keyTypeMetaData, comp, root, 1146 args); 1147 } 1148 1149 1152 protected void addFetchAllRowsKey(SqlExp e, SelectExp se) { 1153 for (; e.next != null; e = e.next) ; 1154 e.next = JdbcColumn.toSqlExp(keyColumns, se); 1155 } 1156 1157 1162 public int readRow(ResultSet rs, JdbcLinkCollectionField.LinkRow row) 1163 throws SQLException { 1164 int pos = super.readRow(rs, row); 1165 if (keysAreOIDs) { 1166 OID keyOid = fmd.keyTypeMetaData.createOID(false); 1167 ((JdbcOID)keyOid).copyKeyFields(rs, pos); 1168 row.key = keyOid; 1169 pos += keyColumns.length; 1170 } else { 1171 row.key = keyColumns[0].get(rs, pos++); 1172 } 1173 return pos; 1174 } 1175 1176 1180 public void writeRow(PreparedStatement ps, LinkRow row) 1181 throws SQLException { 1182 row.owner.setCmd(fmd.classMetaData); 1183 int pos = row.owner.setParams(ps, 1); 1184 if (keysAreOIDs) { 1185 JdbcGenericOID k = (JdbcGenericOID)row.key; 1186 k.setCmd(fmd.classMetaData); 1187 pos = k.setParams(ps, pos); 1188 } else { 1189 keyColumns[0].set(ps, pos++, row.key); 1190 } 1191 if (valuesAreOIDs) { 1192 JdbcGenericOID v = (JdbcGenericOID)row.value; 1193 v.setCmd(fmd.classMetaData); 1194 v.setParams(ps, pos); 1195 } else { 1196 valueColumns[0].set(ps, pos, row.value); 1197 } 1198 } 1199 1200} 1201 | Popular Tags |