1 2 12 package com.versant.core.jdbc.metadata; 13 14 import com.versant.core.common.Debug; 15 import com.versant.core.common.*; 16 import com.versant.core.metadata.*; 17 import com.versant.core.metadata.parser.JdoElement; 18 import com.versant.core.metadata.parser.JdoExtension; 19 import com.versant.core.metadata.parser.JdoExtensionKeys; 20 import com.versant.core.jdo.query.*; 21 import com.versant.core.server.StateContainer; 22 import com.versant.core.server.PersistGraph; 23 import com.versant.core.jdbc.*; 24 import com.versant.core.jdbc.query.JdbcJDOQLCompiler; 25 import com.versant.core.jdbc.sql.JdbcNameGenerator; 26 import com.versant.core.jdbc.sql.SqlDriver; 27 import com.versant.core.jdbc.sql.exp.*; 28 import com.versant.core.util.CharBuf; 29 30 import java.io.PrintStream ; 31 import java.sql.Connection ; 32 import java.sql.PreparedStatement ; 33 import java.sql.ResultSet ; 34 import java.sql.SQLException ; 35 import java.util.ArrayList ; 36 import java.util.HashSet ; 37 import java.util.List ; 38 import java.lang.reflect.Array ; 39 40 43 public class JdbcLinkCollectionField extends JdbcCollectionField { 44 45 49 public JdbcLinkCollectionField inverse; 50 53 public boolean readOnly; 54 57 public JdbcTable linkTable; 58 62 public JdbcColumn[] valueColumns; 63 66 public boolean valuesAreOIDs; 67 68 private transient boolean createValueConstraint; 69 private transient String valueConstraintName; 70 private transient boolean doNotCreateTable; 71 72 private transient String deleteRowSql; 74 private transient String deleteAllRowsSql; 76 private transient String insertRowSql; 78 79 private static final int WINDOW_SIZE = 20; 81 private static final float FUDGE_FACTOR = 1.5f; 83 private static final int MIN_LEN = 4; 85 86 protected transient int fetchCount; 88 protected transient float avgRowCount; 90 protected transient int expansionCount; 94 95 98 public void getTables(HashSet tables) { 99 if (!readOnly && !doNotCreateTable && linkTable != null) { 100 tables.add(linkTable); 101 } 102 } 103 104 public void dump(PrintStream out, String indent) { 105 super.dump(out, indent); 106 String is = indent + " "; 107 out.println(is + "inverse " + inverse); 108 out.println(is + "readOnly " + readOnly); 109 out.println(is + "valuesAreOIDs " + valuesAreOIDs); 110 out.println(is + "linkTable " + linkTable); 111 if (valueColumns == null) { 112 out.println(is + "valueColumns null"); 113 } else { 114 for (int i = 0; i < valueColumns.length; i++) { 115 out.println(is + "valueColumns[" + i + "] " + valueColumns[i]); 116 } 117 } 118 } 119 120 124 public void processMetaData(JdoElement context, JdbcMetaDataBuilder mdb, 125 boolean quiet) { 126 super.processMetaData(context, mdb, quiet); 127 128 JdoExtension[] extensions = getExtensions(); 129 130 JdoExtension ext = JdoExtension.find(JdoExtensionKeys.INVERSE, 132 extensions); 133 if (ext != null) { 134 processInverse(mdb, ext); 135 return; 136 } 137 138 valuesAreOIDs = fmd.elementTypeMetaData != null; 139 if (valuesAreOIDs) { 140 if (fmd.ordered || allowNulls()) { 141 useJoin = JdbcField.USE_JOIN_OUTER; 142 } else { 143 useJoin = JdbcField.USE_JOIN_INNER; 144 } 145 } else { 146 useJoin = JdbcField.USE_JOIN_NO; 147 } 148 149 ext = JdoExtension.find(JdoExtensionKeys.MANAGED, extensions); 150 if (ext != null) { 151 if (fmd.category == MDStatics.CATEGORY_ARRAY && ext.getBoolean()) { 152 throw BindingSupportImpl.getInstance().invalidOperation( 153 "The managed option is not supported for arrays: " + fmd.name); 154 } 155 fmd.managed = ext.getBoolean(); 156 } else { 157 if (fmd.category != MDStatics.CATEGORY_ARRAY) { 158 fmd.managed = mdb.getJdbcConfig().managedManyToMany; 159 } else { 160 fmd.managed = false; 161 } 162 } 163 164 ClassMetaData cmd = fmd.classMetaData; 165 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 166 ArrayList cols = new ArrayList (); 167 JdoExtension link = JdoExtension.find(JdoExtensionKeys.JDBC_LINK_TABLE, 168 extensions); 169 JdoExtension[] linkNested = link == null ? null : link.nested; 170 171 ext = JdoExtension.find(JdoExtensionKeys.JDBC_OWNER_REF, linkNested); 173 JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder(cmd, mdb, 174 fmd.classMetaData, context, 175 JdbcMetaDataBuilder.OWNER_REF_FIELDNAME, 176 ext == null ? null : ext.nested, quiet); 177 ourPkColumns = rdb.getCols(); 178 cols.addAll(rdb.getColsList()); 179 boolean pkConstraint = !rdb.isDoNotCreateConstraint(); 180 String pkConstraintName = rdb.getConstraintName(); 181 182 if (fmd.ordered) { 184 ext = JdoExtension.find(JdoExtensionKeys.JDBC_SEQUENCE, linkNested); 185 sequenceColumn = mdb.createColumn(ext == null ? null : ext.nested, 186 JdbcMetaDataBuilder.SEQUENCE_FIELDNAME, Integer.TYPE); 187 cols.add(sequenceColumn); 188 } 189 190 completeKeyAndValueColumnMetaData(jdbcClass, cols, context, linkNested, 191 mdb, quiet); 192 193 linkTable = new JdbcTable(); 195 linkTable.comment = fmd.getTypeQName(); 196 createLinkTablePK(); 197 linkTable.sqlDriver = mdb.getSqlDriver(); 198 linkTable.cols = new JdbcColumn[cols.size()]; 199 cols.toArray(linkTable.cols); 200 linkTable.setTableOnCols(); 201 202 List constraints = createConstraints(pkConstraint, pkConstraintName); 205 linkTable.constraints = new JdbcConstraint[constraints.size()]; 206 constraints.toArray(linkTable.constraints); 207 208 ext = JdoExtension.find(JdoExtensionKeys.JDBC_DO_NOT_CREATE_TABLE, 210 linkNested); 211 doNotCreateTable = ext != null && ext.getBoolean(); 212 String linkTableNameForNamegen = null; 213 214 JdbcNameGenerator namegen = mdb.getNameGenerator(); 220 ext = JdoExtension.find(JdoExtensionKeys.JDBC_TABLE_NAME, linkNested); 221 if (ext == null) { 222 nameLinkTable(namegen, jdbcClass); 223 } else { 224 try { 225 namegen.addTableName(linkTable.name = ext.getString()); 226 } catch (IllegalArgumentException e) { 227 if (!doNotCreateTable) { 228 throw BindingSupportImpl.getInstance().runtime(e.getMessage() + "\n" + 229 context.getContext(), e); 230 } 231 linkTableNameForNamegen = linkTable.name + System.currentTimeMillis(); 236 namegen.addTableName(linkTableNameForNamegen); 237 } 238 } 239 String linkTableName = linkTable.name; 240 if (linkTableNameForNamegen == null) linkTableNameForNamegen = linkTableName; 241 242 if (!doNotCreateTable) { 244 if (linkTable.pkConstraintName == null) { 245 linkTable.pkConstraintName = 246 namegen.generatePkConstraintName(linkTableName); 247 } else { 248 namegen.addPkConstraintName(linkTableName, 249 linkTable.pkConstraintName); 250 } 251 } 252 253 for (int i = 0; i < linkTable.cols.length; i++) { 255 try { 256 linkTable.cols[i].addColumnNames(linkTableNameForNamegen, 257 namegen); 258 } catch (IllegalArgumentException e) { 259 if (!doNotCreateTable) { 260 throw BindingSupportImpl.getInstance().runtime(e.getMessage() + "\n" + 261 context.getContext(), e); 262 } 263 } 265 } 266 267 String [] pkNames = jdbcClass.table.getPkNames(); 269 String [] ourPkNames = JdbcColumn.getColumnNames(ourPkColumns); 270 namegen.generateLinkTableMainRefNames(linkTableNameForNamegen, pkNames, 271 ourPkNames); 272 JdbcColumn.setColumnNames(ourPkColumns, ourPkNames); 273 274 if (sequenceColumn != null && sequenceColumn.name == null) { 276 sequenceColumn.name = namegen.generateLinkTableSequenceName( 277 linkTableNameForNamegen); 278 } 279 280 nameKeyAndValueColumns(namegen, linkTableNameForNamegen); 282 283 if (!doNotCreateTable) { 285 for (int i = 0; i < linkTable.constraints.length; i++) { 286 JdbcConstraint c = linkTable.constraints[i]; 287 if (c.name != null) { 288 namegen.addRefConstraintName(linkTableName, c.name); 289 } else { 290 String [] fkNames = JdbcColumn.getColumnNames(c.srcCols); 291 String [] refPkNames = JdbcColumn.getColumnNames(c.dest.pk); 292 c.name = namegen.generateRefConstraintName(linkTableName, 293 c.dest.name, fkNames, refPkNames); 294 } 295 } 296 } 297 298 if (doNotCreateTable) namegen.removeTableName(linkTableNameForNamegen); 302 303 syncWithInverse(mdb); 305 } 306 307 310 protected List createConstraints(boolean pkConstraint, 311 String pkConstraintName) { 312 ArrayList constraints = new ArrayList (); 313 314 if (pkConstraint) { 315 JdbcConstraint mainCon = new JdbcConstraint(); 316 mainCon.src = linkTable; 317 mainCon.srcCols = ourPkColumns; 318 mainCon.dest = ((JdbcClass)fmd.classMetaData.storeClass).table; 319 mainCon.name = pkConstraintName; 320 constraints.add(mainCon); 321 } 322 323 if (createValueConstraint && valuesAreOIDs 324 && fmd.elementTypeMetaData.storeClass != null) { 325 JdbcConstraint valueCon = new JdbcConstraint(); 326 valueCon.src = linkTable; 327 valueCon.srcCols = valueColumns; 328 valueCon.dest = ((JdbcClass)fmd.elementTypeMetaData.storeClass).table; 329 valueCon.name = valueConstraintName; 330 constraints.add(valueCon); 331 } 332 333 return constraints; 334 } 335 336 339 private JdoExtension[] getExtensions() { 340 switch (fmd.category) { 341 case MDStatics.CATEGORY_ARRAY: 342 if (fmd.jdoArray != null) return fmd.jdoArray.extensions; 343 return null; 344 case MDStatics.CATEGORY_COLLECTION: 345 if (fmd.jdoCollection != null) return fmd.jdoCollection.extensions; 346 return null; 347 case MDStatics.CATEGORY_MAP: 348 if (fmd.jdoMap != null) return fmd.jdoMap.extensions; 349 return null; 350 } 351 throw BindingSupportImpl.getInstance().internal( 352 "invalid category: " + fmd.category); 353 } 354 355 358 protected void createLinkTablePK() { 359 if (sequenceColumn != null) { 360 linkTable.setPk(JdbcColumn.concat(ourPkColumns, sequenceColumn)); 361 } else { 362 linkTable.setPk(JdbcColumn.concat(ourPkColumns, valueColumns)); 363 } 364 } 365 366 369 protected void nameKeyAndValueColumns(JdbcNameGenerator namegen, 370 String linkTableNameForNamegen) { 371 if (valuesAreOIDs) { 373 String [] valuePkNames = JdbcColumn.getColumnNames( 374 ((JdbcClass)fmd.elementTypeMetaData.storeClass).table.pk); 375 String [] linkValueRefNames = JdbcColumn.getColumnNames( 376 valueColumns); 377 namegen.generateLinkTableValueRefNames(linkTableNameForNamegen, 378 valuePkNames, fmd.elementType.getName(), linkValueRefNames, 379 false); 380 JdbcColumn.setColumnNames(valueColumns, linkValueRefNames); 381 } else { 382 JdbcColumn c = valueColumns[0]; 383 if (c.name == null) { 384 c.name = namegen.generateLinkTableValueName( 385 linkTableNameForNamegen, 386 fmd.elementType, false); 387 } 388 } 389 } 390 391 394 protected void completeKeyAndValueColumnMetaData(JdbcClass jdbcClass, 395 ArrayList cols, 396 JdoElement context, JdoExtension[] linkNested, 397 JdbcMetaDataBuilder mdb, boolean quiet) { 398 399 JdoExtension ext = JdoExtension.find(JdoExtensionKeys.JDBC_VALUE, 401 linkNested); 402 if (fmd.elementTypeMetaData != null) { JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder( 404 fmd.classMetaData, mdb, 405 fmd.elementTypeMetaData, context, 406 JdbcMetaDataBuilder.VALUE_FIELDNAME, 407 ext == null ? null : ext.nested, quiet); 408 createValueConstraint = !rdb.isDoNotCreateConstraint(); 409 valueConstraintName = rdb.getConstraintName(); 410 valueColumns = rdb.getCols(); 411 cols.addAll(rdb.getColsList()); 412 } else { 413 if (fmd.elementType == Object .class) { 414 if (fmd.classMetaData.jmd.testing) { 415 fmd.setElementType(String .class); } else { 417 throw BindingSupportImpl.getInstance().runtime("You must specify the element-type (or value-type for maps) " + 418 "for collections (and maps)\n" + 419 fmd + "\n" + context.getContext()); 420 } 421 } 422 423 JdbcColumn vc = null; 424 if (fmd.category == MDStatics.CATEGORY_COLLECTION) { 425 vc = mdb.createColumn(ext == null ? null : ext.nested, 426 JdbcMetaDataBuilder.VALUE_FIELDNAME, fmd.elementType); 427 } else if (fmd.category == MDStatics.CATEGORY_ARRAY) { 428 vc = mdb.createColumn(ext == null ? null : ext.nested, 429 JdbcMetaDataBuilder.VALUE_FIELDNAME, fmd.elementType); 430 if (Debug.DEBUG) { 431 if (fmd.componentType != fmd.elementType) { 432 throw new RuntimeException (); 433 } 434 } 435 } else if (fmd.category == MDStatics.CATEGORY_MAP) { 436 vc = mdb.createColumn(ext == null ? null : ext.nested, 437 JdbcMetaDataBuilder.VALUE_FIELDNAME, fmd.elementType); 438 } else { 439 throw BindingSupportImpl.getInstance().internal(""); 440 } 441 442 valueColumns = new JdbcColumn[]{vc}; 443 cols.add(vc); 444 } 445 446 boolean nulls = allowNulls(); 448 for (int i = 0; i < valueColumns.length; i++) { 449 JdbcColumn valueColumn = valueColumns[i]; 450 valueColumn.setNulls(nulls); 451 } 452 } 453 454 457 protected void nameLinkTable(JdbcNameGenerator namegen, 458 JdbcClass jdbcClass) { 459 JdbcClass valueTarget = null; 460 if (valuesAreOIDs) valueTarget = (JdbcClass)fmd.elementTypeMetaData.storeClass; 461 linkTable.name = namegen.generateLinkTableName(jdbcClass.table.name, fmd.name, 462 valueTarget == null ? null : valueTarget.table.name); 463 } 464 465 469 public void persistPass2Block(PersistGraph graph, int blockStart, 470 int blockEnd, CharBuf s, Connection con, boolean batchInserts, 471 boolean batchUpdates) throws SQLException { 472 if (Debug.DEBUG) { 473 if (readOnly) { 474 for (int pos = blockStart; pos < blockEnd; pos++) { 475 State ns = graph.getNewState(pos); 476 if (ns.getInternalObjectField(stateFieldNo) != null) { 477 throw BindingSupportImpl.getInstance().internal( 478 "readOnly field in ns"); 479 } 480 } 481 } 482 } 483 if (readOnly) return; 484 if (fmd.ordered) { 485 persistPass2BlockOrdered(graph, blockStart, blockEnd, s, con, 486 batchInserts, batchUpdates); 487 } else { 488 persistPass2BlockUnordered(graph, blockStart, blockEnd, s, con, 489 batchInserts, batchUpdates); 490 } 491 } 492 493 private void persistPass2BlockOrdered(PersistGraph graph, int blockStart, 494 int blockEnd, CharBuf s, Connection con, boolean batchInserts, 495 boolean batchUpdates) throws SQLException { 496 PreparedStatement psdel = null; 497 PreparedStatement psdelAll = null; 498 PreparedStatement psins = null; 499 int delCount = 0; 500 try { 501 String psdelSql = null; 502 String psdelAllSql = null; 503 String psinsSql = null; 504 for (int pos = blockStart; pos < blockEnd; pos++) { 505 State ns = graph.getNewState(pos); 506 if (!ns.containsField(stateFieldNo)) continue; 507 508 OID oid = graph.getOID(pos); 509 if (fmd.category == MDStatics.CATEGORY_ARRAY) { 510 if (!oid.isNew()) { 511 if (psdelAll == null) { 513 psdelAllSql = getDeleteAllLinkTableRowsSql(s); 514 psdelAll = con.prepareStatement(psdelAllSql); 515 } 516 ((JdbcOID)oid).setParams(psdelAll, 1); 517 if (batchUpdates) { 518 psdelAll.addBatch(); 519 } else { 520 try { 521 psdelAll.execute(); 522 } catch (Exception e) { 523 throw mapException(e, 524 "Delete all link table rows failed: " + 525 JdbcUtils.toString(e) + "\n" + 526 "Field: " + fmd.getTypeQName() + "\n" + 527 "Instance: " + oid.toSString() + "\n" + 528 JdbcUtils.getPreparedStatementInfo( 529 psdelAllSql, psdelAll)); 530 } 531 } 532 } 533 534 Object toInsert = ns.getInternalObjectField(stateFieldNo); 535 if (toInsert != null) { 536 if (psins == null) { 537 psinsSql = getInsertLinkTableRowSql(s); 538 psins = con.prepareStatement(psinsSql); 539 } 540 541 if (fmd.componentType.isPrimitive()) { 542 throw BindingSupportImpl.getInstance().unsupported(); 544 } else { 545 insertOrderedLinkTableRows(oid, null, 546 toInsert, psins, batchInserts, psinsSql); 547 } 548 } 549 550 } else { 551 OrderedCollectionDiff diff = 552 (OrderedCollectionDiff)ns.getInternalObjectField( 553 stateFieldNo); 554 if (diff == null || diff.status == CollectionDiff.STATUS_NEW) { 555 if (!oid.isNew()) { 556 if (psdelAll == null) { 557 psdelAllSql = getDeleteAllLinkTableRowsSql(s); 558 psdelAll = con.prepareStatement(psdelAllSql); 559 } 560 ((JdbcOID)oid).setParams(psdelAll, 1); 561 if (batchUpdates) { 562 psdelAll.addBatch(); 563 } else { 564 try { 565 psdelAll.execute(); 566 } catch (Exception e) { 567 throw mapException(e, 568 "Delete all link table rows failed: " + 569 JdbcUtils.toString(e) + "\n" + 570 "Field: " + fmd.getTypeQName() + "\n" + 571 "Instance: " + oid.toSString() + "\n" + 572 JdbcUtils.getPreparedStatementInfo( 573 psdelAllSql, psdelAll)); 574 } 575 } 576 } 577 } else { 578 int[] deleted = diff.deletedIndexes; 579 if (deleted != null && deleted.length > 0) { 580 if (psdel == null) { 581 psdelSql = getDeleteLinkTableRowSql(s); 582 psdel = con.prepareStatement(psdelSql); 583 } 584 deletedOrderedLinkTableRows(oid, deleted, psdel, 585 batchUpdates, psdelSql); 586 delCount += deleted.length; 587 } 588 } 589 590 if (diff != null) { 591 Object [] insertedValues = diff.insertedValues; 592 if (insertedValues != null && insertedValues.length > 0) { 593 if (psins == null) { 594 psinsSql = getInsertLinkTableRowSql(s); 595 psins = con.prepareStatement(psinsSql); 596 } 597 insertOrderedLinkTableRows(oid, 598 diff.insertedIndexes, 599 insertedValues, psins, batchInserts, 600 psinsSql); 601 } 602 } 603 } 604 } 605 if (batchUpdates) { 606 execLinkTableBatchDeletes(delCount, psdel, psdelSql, 607 psdelAll, psdelAllSql); 608 } 609 if (batchInserts && psins != null) { 610 execLinkTableBatchInserts(psins, psinsSql); 611 } 612 } finally { 613 cleanup(psdel); 614 cleanup(psdelAll); 615 cleanup(psins); 616 } 617 } 618 619 protected void execLinkTableBatchInserts(PreparedStatement psins, 620 String psinsSql) { 621 try { 622 psins.executeBatch(); 623 } catch (SQLException e) { 624 throw mapException(e, 625 "Link table batch insert failed: " + 626 JdbcUtils.toString(e) + "\n" + 627 "Field: " + fmd.getTypeQName() + "\n" + 628 JdbcUtils.getPreparedStatementInfo(psinsSql, psins)); 629 } 630 } 631 632 protected void execLinkTableBatchDeletes(int delCount, PreparedStatement psdel, 633 String psdelSql, PreparedStatement psdelAll, String psdelAllSql) { 634 if (delCount > 0) { 635 int[] a; 636 try { 637 a = psdel.executeBatch(); 638 } catch (Exception e) { 639 throw mapException(e, 640 "Link table batch delete failed: " + 641 JdbcUtils.toString(e) + "\n" + 642 "Field: " + fmd.getTypeQName() + "\n" + 643 JdbcUtils.getPreparedStatementInfo(psdelSql, psdel)); 644 } 645 for (int i = 0; i < delCount; i++) { 646 int c = a[i]; 647 if (c <= 0) { 648 String psi = JdbcUtils.getPreparedStatementInfo(psdelSql, 649 psdel, i); 650 if (c == 0) { 651 throw BindingSupportImpl.getInstance().concurrentUpdate("Link table row not found on batch delete: " + 652 "Field: " + fmd.getTypeQName() + "\n" + psi, null); 653 } 654 throw BindingSupportImpl.getInstance().datastore("Unexpected update count for link table row batch delete: " + 655 c + "\nField: " + fmd.getTypeQName() + "\n" + psi); 656 } 657 } 658 } 659 if (psdelAll != null) { 660 try { 661 psdelAll.executeBatch(); 662 } catch (Exception e) { 663 throw mapException(e, 664 "Link table batch delete all failed: " + 665 JdbcUtils.toString(e) + "\n" + 666 "Field: " + fmd.getTypeQName() + "\n" + 667 JdbcUtils.getPreparedStatementInfo(psdelAllSql, 668 psdelAll)); 669 } 670 } 671 } 672 673 676 private void deletedOrderedLinkTableRows(OID oid, int[] deleted, 677 PreparedStatement psdel, boolean batch, String sql) 678 throws SQLException { 679 JdbcColumn sc = sequenceColumn; 680 for (int j = deleted.length - 1; j >= 0; j--) { 681 int pp = ((JdbcOID)oid).setParams(psdel, 1); 682 sc.set(psdel, pp, deleted[j]); 683 if (batch) { 684 psdel.addBatch(); 685 } else { 686 int uc; 687 try { 688 uc = psdel.executeUpdate(); 689 } catch (Exception e) { 690 throw mapException(e, 691 "Delete link table row failed: " + 692 JdbcUtils.toString(e) + "\n" + 693 "Field: " + fmd.getTypeQName() + "\n" + 694 "Sequence: " + deleted[j] + "\n" + 695 "Instance: " + oid.toSString() + "\n" + 696 JdbcUtils.getPreparedStatementInfo(sql, psdel)); 697 } 698 if (uc == 0) { 699 throw BindingSupportImpl.getInstance().concurrentUpdate("Link table row not found: " + 700 "Field: " + fmd.getTypeQName() + "\n" + 701 "Sequence: " + deleted[j] + "\n" + 702 "Instance: " + oid.toSString() + "\n" + 703 JdbcUtils.getPreparedStatementInfo(sql, psdel), oid); 704 } 705 } 706 } 707 } 708 709 712 private void insertOrderedLinkTableRows(OID oid, int[] insertedIndexes, 713 Object _insertedValues, PreparedStatement psins, boolean batch, 714 String sql) throws SQLException { 715 716 Object [] insertedValues = (Object [])_insertedValues; 717 int ilen = insertedValues.length; 718 719 720 if (valuesAreOIDs) { 721 for (int j = 0; j < ilen; j++) { 722 int pp = ((JdbcOID)oid).setParams(psins, 1); 723 sequenceColumn.set(psins, pp++, 724 insertedIndexes == null ? j : insertedIndexes[j]); 725 726 OID _oid = (OID)insertedValues[j]; 727 728 729 730 if (_oid != null) { 731 ((JdbcOID)_oid).setParams(psins, pp); 732 } else { 733 JdbcGenericOID.setNullParams(psins, pp, fmd.elementTypeMetaData); 734 } 735 if (batch) { 736 psins.addBatch(); 737 } else { 738 try { 739 psins.execute(); 740 } catch (Exception e) { 741 throw mapException(e, 742 "Insert link table row failed: " + 743 JdbcUtils.toString(e) + "\n" + 744 "Field: " + fmd.getTypeQName() + "\n" + 745 "Instance: " + oid.toSString() + "\n" + 746 "Link table value[sequence " + insertedIndexes[j] + "]: " + 747 _oid.toSString() + "\n" + 748 JdbcUtils.getPreparedStatementInfo(sql, psins)); 749 } 750 } 751 } 752 } else { 753 JdbcColumn vc = valueColumns[0]; 754 for (int j = 0; j < ilen; j++) { 755 int pp = ((JdbcOID)oid).setParams(psins, 1); 756 sequenceColumn.set(psins, pp++, 757 insertedIndexes == null ? j : insertedIndexes[j]); 758 759 vc.set(psins, pp, insertedValues[j]); 760 761 762 if (batch) { 763 psins.addBatch(); 764 } else { 765 try { 766 psins.execute(); 767 } catch (Exception e) { 768 throw mapException(e, 769 "Insert link table row failed: " + 770 JdbcUtils.toString(e) + "\n" + 771 "Field: " + fmd.getTypeQName() + "\n" + 772 "Instance: " + oid.toSString() + "\n" + 773 "Link table value[sequence " + insertedIndexes[j] + "]: " + 774 775 Utils.toString(insertedValues[j]) + "\n" + 776 777 778 JdbcUtils.getPreparedStatementInfo(sql, psins)); 779 } 780 } 781 } 782 } 783 } 784 785 private void persistPass2BlockUnordered(PersistGraph graph, int blockStart, 786 int blockEnd, CharBuf s, Connection con, boolean batchInserts, 787 boolean batchUpdates) throws SQLException { 788 PreparedStatement psdel = null; 789 PreparedStatement psdelAll = null; 790 PreparedStatement psins = null; 791 int delCount = 0; 792 try { 793 String psdelSql = null; 794 String psdelAllSql = null; 795 String psinsSql = null; 796 for (int pos = blockStart; pos < blockEnd; pos++) { 797 State ns = graph.getNewState(pos); 798 if (!ns.containsField(stateFieldNo)) continue; 799 800 UnorderedCollectionDiff diff = 801 (UnorderedCollectionDiff)ns.getInternalObjectField( 802 stateFieldNo); 803 804 OID oid = graph.getOID(pos); 805 806 if (diff == null || diff.status == CollectionDiff.STATUS_NEW) { 807 if (!oid.isNew()) { 808 if (psdelAll == null) { 809 psdelAllSql = getDeleteAllLinkTableRowsSql(s); 810 psdelAll = con.prepareStatement(psdelAllSql); 811 } 812 ((JdbcOID)oid).setParams(psdelAll, 1); 813 if (batchUpdates) { 814 psdelAll.addBatch(); 815 } else { 816 try { 817 psdelAll.execute(); 818 } catch (Exception e) { 819 throw mapException(e, 820 "Delete all link table rows failed: " + 821 JdbcUtils.toString(e) + "\n" + 822 "Field: " + fmd.getTypeQName() + "\n" + 823 "Instance: " + oid.toSString() + "\n" + 824 JdbcUtils.getPreparedStatementInfo( 825 psdelAllSql, psdelAll)); 826 } 827 } 828 } 829 } else { 830 Object [] deleted = diff.deletedValues; 831 if (deleted != null && deleted.length > 0) { 832 if (psdel == null) { 833 psdelSql = getDeleteLinkTableRowSql(s); 834 psdel = con.prepareStatement(psdelSql); 835 } 836 deleteUnorderedLinkTableRows(oid, deleted, psdel, 837 batchUpdates, psdelSql); 838 delCount += deleted.length; 839 } 840 } 841 842 if (diff != null) { 843 Object [] inserted = diff.insertedValues; 844 if (inserted != null && inserted.length > 0) { 845 if (psins == null) { 846 psinsSql = getInsertLinkTableRowSql(s); 847 psins = con.prepareStatement(psinsSql); 848 } 849 insertUnorderedLinkTableRows(oid, inserted, 850 psins, batchInserts, psinsSql); 851 } 852 } 853 } 854 if (batchUpdates) { 855 execLinkTableBatchDeletes(delCount, psdel, psdelSql, 856 psdelAll, psdelAllSql); 857 } 858 if (batchInserts && psins != null) { 859 execLinkTableBatchInserts(psins, psinsSql); 860 } 861 } finally { 862 cleanup(psdel); 863 cleanup(psdelAll); 864 cleanup(psins); 865 } 866 } 867 868 871 private void deleteUnorderedLinkTableRows(OID oid, Object [] deleted, 872 PreparedStatement psdel, boolean batch, String sql) 873 throws SQLException { 874 if (valuesAreOIDs) { 875 for (int j = deleted.length - 1; j >= 0; j--) { 876 int pp = ((JdbcOID)oid).setParams(psdel, 1); 877 ((JdbcOID)deleted[j]).setParams(psdel, pp); 878 if (batch) { 879 psdel.addBatch(); 880 } else { 881 int uc; 882 try { 883 uc = psdel.executeUpdate(); 884 } catch (Exception e) { 885 throw mapException(e, 886 "Delete link table row failed: " + 887 JdbcUtils.toString(e) + "\n" + 888 "Field: " + fmd.getTypeQName() + "\n" + 889 "Value: " + ((OID)deleted[j]).toSString() + "\n" + 890 "Instance: " + oid.toSString() + "\n" + 891 JdbcUtils.getPreparedStatementInfo(sql, psdel)); 892 } 893 if (uc == 0) { 894 throw BindingSupportImpl.getInstance().concurrentUpdate("Link table row not found: " + 895 "Field: " + fmd.getTypeQName() + "\n" + 896 "Value: " + ((OID)deleted[j]).toSString() + "\n" + 897 "Instance: " + oid.toSString() + "\n" + 898 JdbcUtils.getPreparedStatementInfo(sql, psdel), deleted[j]); 899 } 900 } 901 } 902 } else { 903 JdbcColumn vc = valueColumns[0]; 904 for (int j = deleted.length - 1; j >= 0; j--) { 905 int pp = ((JdbcOID)oid).setParams(psdel, 1); 906 vc.set(psdel, pp, deleted[j]); 907 if (batch) { 908 psdel.addBatch(); 909 } else { 910 int uc; 911 try { 912 uc = psdel.executeUpdate(); 913 } catch (Exception e) { 914 throw mapException(e, 915 "Delete link table row failed: " + 916 JdbcUtils.toString(e) + "\n" + 917 "Field: " + fmd.getTypeQName() + "\n" + 918 "Value: " + Utils.toString(deleted[j]) + "\n" + 919 "Instance: " + oid.toSString() + "\n" + 920 JdbcUtils.getPreparedStatementInfo(sql, psdel)); 921 } 922 if (uc == 0) { 923 throw BindingSupportImpl.getInstance().concurrentUpdate("Link table row not found: " + 924 "Field: " + fmd.getTypeQName() + "\n" + 925 "Value: " + Utils.toString(deleted[j]) + "\n" + 926 "Instance: " + oid.toSString() + "\n" + 927 JdbcUtils.getPreparedStatementInfo(sql, psdel), oid); 928 } 929 } 930 } 931 } 932 } 933 934 937 private void insertUnorderedLinkTableRows(OID oid, Object [] inserted, 938 PreparedStatement psins, boolean batch, String sql) 939 throws SQLException { 940 int ilen = inserted.length; 941 if (valuesAreOIDs) { 942 for (int j = 0; j < ilen; j++) { 943 int pp = ((JdbcOID)oid).setParams(psins, 1); 944 ((JdbcOID)inserted[j]).setParams(psins, pp); 945 if (batch) { 946 psins.addBatch(); 947 } else { 948 try { 949 psins.execute(); 950 } catch (Exception e) { 951 throw mapException(e, 952 "Insert link table row failed: " + 953 JdbcUtils.toString(e) + "\n" + 954 "Field: " + fmd.getTypeQName() + "\n" + 955 "Instance: " + oid.toSString() + "\n" + 956 "Value: " + ((OID)inserted[j]).toSString() + "\n" + 957 JdbcUtils.getPreparedStatementInfo(sql, psins)); 958 } 959 } 960 } 961 } else { 962 JdbcColumn vc = valueColumns[0]; 963 for (int j = 0; j < ilen; j++) { 964 int pp = ((JdbcOID)oid).setParams(psins, 1); 965 vc.set(psins, pp, inserted[j]); 966 if (batch) { 967 psins.addBatch(); 968 } else { 969 try { 970 psins.execute(); 971 } catch (Exception e) { 972 throw mapException(e, 973 "Insert link table row failed: " + 974 JdbcUtils.toString(e) + "\n" + 975 "Field: " + fmd.getTypeQName() + "\n" + 976 "Instance: " + oid.toSString() + "\n" + 977 "Value: " + Utils.toString(inserted[j]) + "\n" + 978 JdbcUtils.getPreparedStatementInfo(sql, psins)); 979 } 980 } 981 } 982 } 983 } 984 985 988 protected String getDeleteLinkTableRowSql(CharBuf s) { 989 if (deleteRowSql == null) { 990 s.clear(); 991 s.append("delete from "); 992 s.append(linkTable.name); 993 s.append(" where "); 994 linkTable.appendWherePK(s); 995 deleteRowSql = s.toString(); 996 } 997 return deleteRowSql; 998 } 999 1000 1003 protected String getDeleteAllLinkTableRowsSql(CharBuf s) { 1004 if (deleteAllRowsSql == null) { 1005 s.clear(); 1006 s.append("DELETE FROM "); 1007 s.append(linkTable.name); 1008 s.append(" WHERE "); 1009 SqlDriver driver = linkTable.sqlDriver; 1010 int nc = ourPkColumns.length; 1011 JdbcColumn sc = ourPkColumns[0]; 1012 s.append(sc.name); 1013 s.append(' '); 1014 s.append('='); 1015 s.append(' '); 1016 driver.appendWhereParam(s, sc); 1017 for (int i = 1; i < nc; i++) { 1018 s.append(" AND "); 1019 sc = ourPkColumns[i]; 1020 s.append(sc.name); 1021 s.append(' '); 1022 s.append('='); 1023 s.append(' '); 1024 driver.appendWhereParam(s, sc); 1025 } 1026 deleteAllRowsSql = s.toString(); 1027 } 1028 return deleteAllRowsSql; 1029 } 1030 1031 1035 protected void getDeleteAllLinkTableRowsSqlWithInList(CharBuf s) { 1036 s.clear(); 1037 s.append("delete from "); 1038 s.append(linkTable.name); 1039 s.append(" where "); 1040 JdbcColumn sc = ourPkColumns[0]; 1041 s.append(sc.name); 1042 s.append(" IN ("); 1043 } 1044 1045 1048 public String getInsertLinkTableRowSql(CharBuf s) { 1049 if (insertRowSql == null) { 1050 s.clear(); 1051 s.append("INSERT INTO "); 1052 s.append(linkTable.name); 1053 s.append('('); 1054 linkTable.appendInsertColumnList(s); 1055 s.append(") VALUES ("); 1056 linkTable.appendInsertValueList(s); 1057 s.append(')'); 1058 insertRowSql = s.toString(); 1059 } 1060 return insertRowSql; 1061 } 1062 1063 1066 private boolean allowNulls() { 1067 return fmd.ordered || fmd.category == MDStatics.CATEGORY_MAP; 1068 } 1069 1070 1074 protected SelectExp getSelectExp(JdbcStorageManager sm, FetchGroupField field, 1075 FgDs[] fgDses) { 1076 SelectExp root = new SelectExp(); 1077 root.table = linkTable; 1078 root.selectList = JdbcColumn.toSqlExp(valueColumns, root); 1079 root.whereExp = JdbcColumn.createEqualsParamExp(ourPkColumns, root); 1080 1081 if (valuesAreOIDs) { 1082 if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO || fmd.ordering != null) { 1083 SelectExp se = new SelectExp(); 1084 JdbcClass valueJdbcClass = (JdbcClass)fmd.elementTypeMetaData.storeClass; 1085 se.table = valueJdbcClass.table; 1086 se.outer = field.jdbcUseJoin != JdbcField.USE_JOIN_INNER; 1087 1088 root.addJoin(valueColumns, se.table.pk, se); 1089 sm.addSelectFetchGroup(se, field.nextFetchGroup, true, 1090 fgDses[0] = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, 1091 field.jdbcUseJoin != JdbcField.USE_JOIN_INNER), 1092 root, valueColumns, this); 1093 1094 if (fmd.ordering != null) { 1095 se.addOrderBy(fmd.ordering, false); 1096 root.orderByList = se.orderByList; 1097 se.orderByList = null; 1098 } 1099 } 1100 } else { 1101 if (fmd.ordering != null) { 1102 boolean desc = fmd.ordering[0].order == OrderNode.ORDER_DESCENDING; 1104 root.orderByList = new OrderExp(valueColumns[0].toSqlExp(root), 1105 desc); 1106 } 1109 } 1110 if (fmd.ordered) { 1111 if (fmd.ordering != null) { 1112 throw BindingSupportImpl.getInstance().internal( 1113 "ordered == true && ordering != null, " + fmd.getTypeQName()); 1114 } 1115 root.orderByList = linkTable.createOrderByPKList(root); 1116 } 1117 return root; 1118 } 1119 1120 public SelectExp getSelectExpFrom(JdbcStorageManager sm, SelectExp joinToExp, FetchGroupField field, 1121 FgDs owningFgDs) { 1122 SelectExp root = getSelectExpFromImp(joinToExp, field, sm, 1123 owningFgDs); 1124 root.selectList = JdbcColumn.toSqlExp(ourPkColumns, root, 1125 root.selectList); 1126 return root; 1127 } 1128 1129 public SelectExp getSelectExpFromImp(SelectExp joinToExp, FetchGroupField field, 1130 JdbcStorageManager sm, FgDs owningFgDs) { 1131 SelectExp root = new SelectExp(); 1132 root.table = linkTable; 1133 root.selectList = JdbcColumn.toSqlExp(valueColumns, root); 1134 1135 if (valuesAreOIDs) { 1136 if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO || fmd.ordering != null) { 1137 SelectExp se = new SelectExp(); 1138 JdbcClass valueJdbcClass = (JdbcClass)fmd.elementTypeMetaData.storeClass; 1139 se.table = valueJdbcClass.table; 1140 se.outer = true; 1141 1142 root.addJoin(valueColumns, se.table.pk, se); 1143 FgDs fgDs = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, se.outer); 1144 sm.addSelectFetchGroup(se, field.nextFetchGroup, true, 1145 fgDs, root, valueColumns, this); 1146 owningFgDs.valueJs = fgDs.getJoinStruct(); 1147 1148 if (fmd.ordering != null) { 1149 se.addOrderBy(fmd.ordering, false); 1150 root.orderByList = se.orderByList; 1151 se.orderByList = null; 1152 } 1153 } 1154 } else { 1155 if (fmd.ordering != null) { 1156 boolean desc = fmd.ordering[0].order == OrderNode.ORDER_DESCENDING; 1158 root.orderByList = new OrderExp(valueColumns[0].toSqlExp(root), 1159 desc); 1160 } 1163 } 1164 if (fmd.ordered) { 1165 if (fmd.ordering != null) { 1166 throw BindingSupportImpl.getInstance().internal( 1167 "ordered == true && ordering != null, " + fmd.getTypeQName()); 1168 } 1169 root.orderByList = linkTable.createOrderByPKList(root); 1170 } 1171 1172 root.outer = true; 1173 joinToExp.addJoin(joinToExp.table.pk, ourPkColumns, root); 1174 joinToExp.appendOrderByExp(root.orderByList); 1175 root.orderByList = null; 1176 return root; 1177 } 1178 1179 1183 public SelectExp getSelectFilterExp(JdbcStorageManager sm, FetchGroupField field, 1184 ColFieldHolder colFHolder) { 1185 SelectExp root = new SelectExp(); 1186 root.table = linkTable; 1187 root.selectList = JdbcColumn.toSqlExp(valueColumns, root); 1188 1189 SqlExp e = JdbcColumn.toSqlExp(ourPkColumns, root, root.selectList); 1191 root.selectList = e; 1192 root.appendOrderByForColumns(ourPkColumns); 1193 1194 if (valuesAreOIDs) { 1195 if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO || fmd.ordering != null) { 1196 SelectExp se = new SelectExp(); 1197 JdbcClass valueJdbcClass = (JdbcClass)fmd.elementTypeMetaData.storeClass; 1198 se.table = valueJdbcClass.table; 1199 se.outer = field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER; 1200 1201 FgDs fgDs = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getFgDs(true, se.outer); 1202 sm.addSelectFetchGroup(se, field.nextFetchGroup, true, 1203 fgDs, root, valueColumns, this); 1204 colFHolder.valueJs = fgDs.getJoinStruct(); 1205 1206 root.addJoin(valueColumns, se.table.pk, se); 1207 if (fmd.ordering != null) { 1208 se.addOrderBy(fmd.ordering, false); 1209 root.appendOrderByExp(se.orderByList); 1210 se.orderByList = null; 1211 } 1212 } 1213 } else { 1214 if (fmd.ordering != null) { 1215 boolean desc = fmd.ordering[0].order == OrderNode.ORDER_DESCENDING; 1217 root.appendOrderByExp(new OrderExp( 1218 valueColumns[0].toSqlExp(root), 1219 desc)); 1220 } 1223 } 1224 if (fmd.ordered) { 1225 if (fmd.ordering != null) { 1226 throw BindingSupportImpl.getInstance().internal( 1227 "ordered == true && ordering != null, " + fmd.getTypeQName()); 1228 } 1229 root.appendOrderByForColumns(linkTable.pkSimpleCols); 1230 } 1231 return root; 1232 } 1233 1234 public SelectExp getSelectFilterJoinExp(boolean value, SelectExp lhSe, 1235 SelectExp rootSe, boolean addRootJoin) { 1236 SelectExp root = new SelectExp(); 1237 root.table = linkTable; 1238 if (valuesAreOIDs) { 1239 SelectExp se = new SelectExp(); 1240 se.table = ((JdbcClass)fmd.elementTypeMetaData.storeClass).table; 1241 root.addJoin(valueColumns, se.table.pk, se); 1242 1243 lhSe.addJoin(lhSe.table.pk, ourPkColumns, root); 1244 1245 return se; 1246 } else { 1247 throw BindingSupportImpl.getInstance().internal( 1248 "This must only be called for pc collections"); 1249 } 1250 } 1251 1252 1255 public int fetchWithFilter(JdbcStorageManager sm, StateContainer oidStates, 1256 FetchGroupField field, ResultSet rs, boolean forUpdate, 1257 OID oidToCheckOn, 1258 OID[] lastReadStateOID, ClassMetaData cmd, 1259 ColFieldHolder colFHolder) throws SQLException { 1260 1261 ClassMetaData valueCmd = fmd.elementTypeMetaData; 1262 boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO; 1263 FetchGroup nextFetchGroup = field.nextFetchGroup; 1264 int valuePkLen = 0; 1265 int keyPkLen = ((JdbcClass)cmd.storeClass).table.pkSimpleColumnCount; 1266 if (joined) valuePkLen = ((JdbcClass)valueCmd.storeClass).table.pkSimpleColumnCount; 1267 int stateOIDPKLen = ((JdbcClass)fmd.classMetaData.storeClass).table.pkSimpleColumnCount; 1268 1269 JdbcColumn vc = valueColumns[0]; 1270 1271 OID rootOid = cmd.createOID(false); 1273 OID prevRootOid = cmd.createOID(false); 1275 OID tmpOID = null; 1276 1277 OID stateOID = fmd.classMetaData.createOID(false); 1278 OID prevStateOID = fmd.classMetaData.createOID(false); 1279 OID tmpStateOID = null; 1280 1281 boolean currentRowValid = false; 1282 boolean prevRowValid = false; 1283 1284 Struct struct = new Struct(); 1285 struct.init(); 1286 int returnState = 0; 1287 1288 FgDs fgDs = null; 1289 if (valuesAreOIDs) { 1290 fgDs = ((JdbcFetchGroup)nextFetchGroup.storeFetchGroup).getExistingFgDs( 1291 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER); 1292 if (colFHolder != null) { 1293 colFHolder.valueJs = fgDs.getJoinStruct(); 1294 } 1295 } 1296 1297 if (lastReadStateOID[0] != null) { 1298 prevRootOid = lastReadStateOID[0]; 1299 stateOID = lastReadStateOID[1]; 1300 currentRowValid = oidStates.containsKey(stateOID); 1301 1302 if (currentRowValid) { 1303 returnState |= STATUS_VALID_ROWS; 1304 if (valuesAreOIDs) { 1305 OID valueOid = valueCmd.createOID(false); 1306 boolean isNull = !((JdbcOID)valueOid).copyKeyFields(rs, 1307 1 + keyPkLen + stateOIDPKLen); 1308 1309 if (!isNull) { 1310 struct.add(valueOid); 1311 } else { 1312 struct.add(null); 1313 } 1314 1315 if (!isNull && joined && oidStates.isStateRequired( 1316 valueOid, 1317 nextFetchGroup)) { 1318 returnState |= STATUS_DATA_ADDED; 1319 State valueState = sm.createStateImp(rs, valueOid, 1320 nextFetchGroup, forUpdate, 1 + valuePkLen + keyPkLen + valuePkLen, 1321 null, true, oidStates, fgDs, false, 1322 false, null); 1323 oidStates.addState(valueOid, valueState); 1324 } 1325 1326 } else { 1327 struct.add(vc.get(rs, 1 + keyPkLen + stateOIDPKLen)); 1328 } 1329 } 1330 1331 tmpOID = rootOid; 1333 rootOid = prevRootOid; 1334 prevRootOid = tmpOID; 1335 1336 tmpStateOID = stateOID; 1338 stateOID = prevStateOID; 1339 prevStateOID = tmpStateOID; 1340 1341 prevRowValid = currentRowValid; 1342 } 1343 1344 for (; rs.next();) { 1345 int index = 1; 1346 ((JdbcOID)rootOid).copyKeyFields(rs, index); 1347 index += keyPkLen; 1348 1349 ((JdbcOID)stateOID).copyKeyFields(rs, index); 1350 index += stateOIDPKLen; 1351 1352 currentRowValid = oidStates.containsKey(stateOID); 1353 1354 if (!stateOID.equals(prevStateOID) && prevRowValid) { 1357 if (updateStateFilter(struct, oidStates.get(prevStateOID))) { 1358 returnState |= STATUS_DATA_ADDED; 1359 } 1360 1361 updateStatistics(struct.size); 1362 if (oidToCheckOn.equals(prevRootOid) && !oidToCheckOn.equals( 1363 rootOid)) { 1364 lastReadStateOID[0] = rootOid; 1365 lastReadStateOID[1] = stateOID; 1366 returnState |= STATUS_VALID_ROWS; 1367 return returnState; 1368 } 1369 1370 struct.init(); 1371 } 1372 1373 if (currentRowValid) { 1374 returnState |= STATUS_VALID_ROWS; 1375 if (valuesAreOIDs) { 1376 OID valueOid = valueCmd.createOID(false); 1377 boolean isNull = !((JdbcOID)valueOid).copyKeyFields(rs, index); 1378 index += valuePkLen; 1379 1380 if (!isNull) { 1381 struct.add(valueOid); 1382 } else { 1383 struct.add(null); 1384 } 1385 1386 if (!isNull && joined && oidStates.isStateRequired( 1387 valueOid, 1388 nextFetchGroup)) { 1389 State valueState = sm.createStateImp(rs, valueOid, 1390 nextFetchGroup, forUpdate, index, 1391 null, true, oidStates, 1392 ((JdbcFetchGroup)nextFetchGroup.storeFetchGroup).getFgDs( 1393 true, field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER), 1394 false, false, null); 1395 oidStates.addState(valueOid, valueState); 1396 } 1397 } else { 1398 struct.add(vc.get(rs, index)); 1399 } 1400 } 1401 1402 tmpOID = rootOid; 1404 rootOid = prevRootOid; 1405 prevRootOid = tmpOID; 1406 1407 tmpStateOID = stateOID; 1409 stateOID = prevStateOID; 1410 prevStateOID = tmpStateOID; 1411 1412 prevRowValid = currentRowValid; 1413 } 1414 1415 rs.close(); 1416 returnState |= STATUS_CLOSED; 1417 if ((returnState & STATUS_VALID_ROWS) == STATUS_VALID_ROWS) { 1418 if (updateStateFilter(struct, oidStates.get(prevStateOID))) { 1419 returnState |= STATUS_DATA_ADDED; 1420 } 1421 } 1422 return returnState; 1423 } 1424 1425 private boolean updateStateFilter(Struct struct, State state) { 1426 if (state == null) return false; 1427 if (struct.values == null) struct.values = EMPTY_OBJECT_ARRAY; 1428 1429 if (Debug.DEBUG) { 1430 if (!state.containsField(fmd.stateFieldNo) 1431 || state.getInternalObjectField(fmd.stateFieldNo) == null) { 1432 throw BindingSupportImpl.getInstance().internal(""); 1433 } 1434 } 1435 1436 if (state.getInternalObjectField(fmd.stateFieldNo) == PRE_GEN_EMPTY_OBJECT_ARRAY) { 1437 state.setInternalObjectField(fmd.stateFieldNo, 1438 struct.asArray(getStructArrayType())); 1439 return true; 1440 } 1441 return false; 1442 } 1443 1444 private Class getStructArrayType() { 1445 if (valuesAreOIDs) { 1446 return OID.class; 1447 } else if (fmd.category == MDStatics.CATEGORY_ARRAY) { 1448 return fmd.componentType; 1449 } else { 1450 return Object .class; 1451 } 1452 } 1453 1454 private class Struct { 1455 1456 public int len; 1457 1458 public Object [] values; 1459 1460 1461 public int size; 1462 1463 public void init() { 1464 len = (int)(avgRowCount * FUDGE_FACTOR); 1465 if (len < MIN_LEN) len = 0; 1466 values = len == 0 ? null : 1467 (Object []) 1468 1469 Array.newInstance(getStructArrayType(), len); 1470 if (Debug.DEBUG) { 1471 if (((fetchCount + 1) % 10) == 0) { 1472 System.out.println("JdbcLinkCollectionField.fetch" + 1473 " avgRowCount = " + avgRowCount + " " + 1474 " len = " + len + " " + 1475 " expansionCount = " + expansionCount + " " + 1476 " fetchCount = " + fetchCount); 1477 } 1478 } 1479 size = 0; 1480 } 1481 1482 public void add(Object value) { 1483 if (!fmd.ordered && value == null) { 1484 return; 1486 } 1487 if (size == len) { 1489 if (len == 0) { 1490 values = 1491 (Object []) 1492 1493 Array.newInstance(getStructArrayType(), 1494 len = MIN_LEN); 1495 } else { 1496 len = len * 3 / 2 + 1; 1497 1498 Object [] a = (Object [])Array.newInstance( 1499 getStructArrayType(), len); 1500 System.arraycopy(values, 0, a, 0, size); 1501 1502 1503 values = a; 1504 expansionCount++; 1505 } 1506 } 1507 1508 1509 values[size++] = value; 1510 1511 1512 } 1513 1514 1517 public Object asArray(Class componentType) { 1518 1519 Object [] a = (Object [])Array.newInstance(componentType, size); 1520 System.arraycopy(values, 0, a, 0, size); 1521 1522 1523 return a; 1524 } 1525 } 1526 1527 public void fillStateWithEmpty(FetchGroupField field, State state) { 1528 if (!state.containsField(fmd.stateFieldNo)) { 1529 state.setInternalObjectField(fmd.stateFieldNo, 1530 PRE_GEN_EMPTY_OBJECT_ARRAY); 1531 } 1532 } 1533 1534 1537 public int fetch(JdbcStorageManager sm, OID oid, State state, 1538 FetchGroupField field, boolean forUpdate, 1539 StateContainer container, boolean fetchPass2Fields, 1540 ColFieldHolder colFHolder) 1541 throws SQLException { 1542 String sql = forUpdate ? field.jdbcSelectSqlForUpdate : field.jdbcSelectSql; 1543 1544 FgDs[] fgDses = new FgDs[1]; 1545 1546 if (sql == null) { 1547 SelectExp se = getSelectExp(sm, field, fgDses); 1548 1549 CharBuf s = sm.generateSql(se); 1550 sql = s.toString(); 1551 if (forUpdate) { 1552 field.jdbcSelectSqlForUpdate = sql; 1553 } else { 1554 field.jdbcSelectSql = sql; 1555 } 1556 } 1557 1558 if (valuesAreOIDs) { 1559 fgDses[0] = ((JdbcFetchGroup)field.nextFetchGroup.storeFetchGroup).getExistingFgDs( 1560 true, field.jdbcUseJoin != JdbcField.USE_JOIN_INNER); 1561 if (colFHolder != null) { 1562 colFHolder.valueJs = fgDses[0].getJoinStruct(); 1563 } 1564 } 1565 1566 final Struct struct = new Struct(); 1567 1568 PreparedStatement ps = null; 1569 ResultSet rs = null; 1570 try { 1571 ps = sm.con().prepareStatement(sql); 1572 ((JdbcOID)oid).setParams(ps, 1); 1573 try { 1574 rs = ps.executeQuery(); 1575 } catch (Exception e) { 1576 throw mapException(e, 1577 "Fetch link table rows failed: " + 1578 JdbcUtils.toString(e) + "\n" + 1579 "Field: " + fmd.getTypeQName() + "\n" + 1580 "Instance: " + oid.toSString() + "\n" + 1581 JdbcUtils.getPreparedStatementInfo(sql, ps)); 1582 } 1583 1584 if (valuesAreOIDs) { 1585 if (colFHolder != null) colFHolder.valueJs = fgDses[0].getJoinStruct(); 1586 final boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO 1587 || fmd.ordering != null; 1588 final int startIndex = 1 + 1589 ((JdbcClass)fmd.elementTypeMetaData.storeClass).table.pkSimpleColumnCount; 1590 1591 for (; rs.next();) { 1592 OID valueOid = fmd.elementTypeMetaData.createOID(false); 1593 if (((JdbcOID)valueOid).copyKeyFields(rs, 1)) { 1594 struct.add(valueOid); 1595 if (joined && container.isStateRequired(valueOid, 1596 field.nextFetchGroup)) { 1597 container.addState(valueOid, 1598 sm.createStateImp(rs, 1599 valueOid, field.nextFetchGroup, 1600 forUpdate, 1601 startIndex, null, true, 1602 container, 1603 fgDses[0], fetchPass2Fields, false, 1604 null)); 1605 } 1606 } else { 1607 struct.add(null); 1608 } 1609 } 1610 } else { 1611 for (; rs.next();) { 1612 struct.add( 1613 valueColumns[0].get(rs, 1 )); 1614 } 1615 } 1616 1617 Object data; 1620 if (struct.values == null) { 1621 1622 data = EMPTY_OBJECT_ARRAY; 1623 } else { 1624 data = struct.asArray(getStructArrayType()); 1625 } 1626 state.setInternalObjectField(fmd.stateFieldNo, data); 1627 updateStatistics(struct.size); 1628 return struct.size; 1629 } finally { 1630 cleanup(rs); 1631 cleanup(ps); 1632 } 1633 } 1634 1635 1638 public int fetchFrom(ResultSet rs, OID oid, State state, 1639 FetchGroupField field, boolean forUpdate, 1640 StateContainer container, 1641 boolean fetchPass2Fields, int colIndex, 1642 FetchInfo fetchInfo, JdbcStorageManager sm) throws SQLException { 1643 final Struct struct = new Struct(); 1644 if (valuesAreOIDs) { 1645 ClassMetaData valueCmd = fmd.elementTypeMetaData; 1646 boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO; 1647 FetchGroup nextFetchGroup = field.nextFetchGroup; 1648 int valuePkLen = 0; 1649 if (joined) valuePkLen = ((JdbcClass)valueCmd.storeClass).table.pkSimpleColumnCount; 1650 boolean first = true; 1651 for (; ;) { 1652 boolean mustBreak = false; 1653 if (first) { 1654 first = false; 1655 mustBreak = updateForFirstRow(fetchInfo, mustBreak, rs, 1656 colIndex, oid); 1657 } else { 1658 if (!rs.next()) { 1659 fetchInfo.onNextRow = false; 1660 fetchInfo.finished = true; 1661 mustBreak = true; 1662 } else { 1663 fetchInfo.onNextRow = true; 1664 mustBreak = checkKeyOid(rs, colIndex, fetchInfo, mustBreak, 1665 oid); 1666 } 1667 } 1668 if (mustBreak) break; 1669 1670 OID valueOid = valueCmd.createOID(false); 1671 if (((JdbcOID)valueOid).copyKeyFields(rs, colIndex + ourPkColumns.length)) { 1672 struct.add(valueOid); 1673 if (joined && container.isStateRequired(valueOid, 1674 nextFetchGroup)) { 1675 State valueState = sm.createStateImp(rs, 1676 valueOid, nextFetchGroup, forUpdate, 1677 colIndex + valuePkLen + ourPkColumns.length, null, 1678 true, container, 1679 ((JdbcFetchGroup)nextFetchGroup.storeFetchGroup).getFgDs(true, true), 1680 fetchPass2Fields, false, null); 1681 container.addState(valueOid, valueState); 1682 } 1683 } else { 1684 struct.add(null); 1685 } 1686 } 1687 } else { 1688 boolean mustBreak = false; 1689 boolean first = true; 1690 for (; ;) { 1691 if (first) { 1692 first = false; 1693 mustBreak = updateForFirstRow(fetchInfo, mustBreak, rs, 1694 colIndex, oid); 1695 } else { 1696 if (!rs.next()) break; 1697 fetchInfo.onNextRow = true; 1698 mustBreak = checkKeyOid(rs, colIndex, fetchInfo, mustBreak, 1699 oid); 1700 } 1701 if (mustBreak) break; 1702 struct.add( 1703 valueColumns[0].get(rs, colIndex + ourPkColumns.length )); 1704 } 1705 } 1706 Object data; 1709 if (struct.values == null) { 1710 1711 data = EMPTY_OBJECT_ARRAY; 1712 } else { 1713 data = struct.asArray(getStructArrayType()); 1714 } 1715 state.setInternalObjectField(fmd.stateFieldNo, data); 1716 updateStatistics(struct.size); 1717 return struct.size; 1718 } 1719 1720 private void updateStatistics(int size) { 1721 int fc = ++fetchCount; 1724 if (fc > WINDOW_SIZE) { 1725 fc = WINDOW_SIZE; 1726 } else if (fc == 1) { 1727 avgRowCount = size; 1728 } else if (fc < 0) { 1729 fc = fetchCount = WINDOW_SIZE; 1730 } else { 1731 avgRowCount = (avgRowCount * (fc - 1) + size) / fc; 1732 } 1733 } 1734 1735 1739 public void deletePass2Block(DeletePacket graph, int blockStart, 1740 int blockEnd, CharBuf s, Connection con, boolean batch) 1741 throws SQLException { 1742 if (readOnly) return; 1743 PreparedStatement ps = null; 1744 try { 1745 final int count = blockEnd - blockStart; 1746 boolean useInList = (ourPkColumns.length == 1) && (count > 1); 1747 if (!batch && !useInList) { 1748 ps = deleteOneByOne(s, con, ps, blockStart, blockEnd, graph); 1750 } else { 1751 if (useInList) { 1752 ps = deleteWithInList(s, count, con, ps, blockStart, blockEnd, graph); 1753 } else if (batch) { 1754 ps = deleteWithBatch(s, con, ps, blockStart, blockEnd, graph); 1755 } 1756 } 1757 } finally { 1758 cleanup(ps); 1759 } 1760 } 1761 1762 private PreparedStatement deleteWithBatch(CharBuf s, Connection con, 1763 PreparedStatement ps, int blockStart, int blockEnd, 1764 DeletePacket graph) throws SQLException { 1765 String sql = getDeleteAllLinkTableRowsSql(s); 1766 ps = con.prepareStatement(sql); 1767 for (int pos = blockStart; pos < blockEnd; pos++) { 1768 ((JdbcOID)graph.oids[pos]).setParams(ps, 1); 1769 ps.addBatch(); 1770 } 1771 try { 1772 ps.executeBatch(); 1773 } catch (Exception e) { 1774 throw mapException(e, 1775 "Batch delete link table rows failed: " + 1776 JdbcUtils.toString(e) + "\n" + 1777 "Field: " + fmd.getTypeQName() + "\n" + 1778 JdbcUtils.getPreparedStatementInfo(sql, ps)); 1779 } 1780 return ps; 1781 } 1782 1783 private PreparedStatement deleteWithInList(CharBuf s, int count, 1784 Connection con, PreparedStatement ps, int blockStart, int blockEnd, 1785 DeletePacket graph) throws SQLException { 1786 SqlDriver driver = getSqlDriver(); 1787 1788 if (count > driver.getMaxInOperands()) { 1789 final int maxInOps = driver.getMaxInOperands(); 1791 int amountOfFullRuns = count/driver.getMaxInOperands(); 1792 1793 final int amountLeft = count % driver.getMaxInOperands();; 1794 String sql = null; 1795 int pos = blockStart; 1796 final String param = driver.getSqlParamString(ourPkColumns[0].jdbcType); 1797 getDeleteAllLinkTableRowsSqlWithInList(s); 1798 if (amountLeft > 0) { 1799 for (int i = 0; i < amountLeft; i++) { 1800 if (i != 0) s.append(","); 1801 s.append(param); 1802 } 1803 s.append(")"); 1804 1805 sql = s.toString(); 1806 ps = con.prepareStatement(sql); 1807 for (int curIndex = 0; curIndex < amountLeft; curIndex++, pos++) { 1808 ((JdbcOID)graph.oids[pos]).setParams(ps, curIndex + 1); 1809 } 1810 try { 1811 ps.execute(); 1812 } catch (Exception e) { 1813 throw mapException(e, 1814 "Batch delete link table rows failed: " + 1815 JdbcUtils.toString(e) + "\n" + 1816 "Field: " + fmd.getTypeQName() + "\n" + 1817 JdbcUtils.getPreparedStatementInfo(sql, ps)); 1818 } 1819 s.set(s.size() - 1, ','); 1820 } 1821 1822 for (int i = 0; i < maxInOps - amountLeft; i++) { 1823 if (i != 0) s.append(","); 1824 s.append(param); 1825 } 1826 s.append(")"); 1827 1828 sql = s.toString(); 1829 ps = con.prepareStatement(sql); 1830 for (int i = 0; i < amountOfFullRuns; i ++) { 1831 for (int curIndex = 0; curIndex < maxInOps; curIndex++, pos++) { 1832 ((JdbcOID)graph.oids[pos]).setParams(ps, curIndex + 1); 1833 } 1834 try { 1835 ps.execute(); 1836 } catch (Exception e) { 1837 throw mapException(e, 1838 "Batch delete link table rows failed: " + 1839 JdbcUtils.toString(e) + "\n" + 1840 "Field: " + fmd.getTypeQName() + "\n" + 1841 JdbcUtils.getPreparedStatementInfo(sql, ps)); 1842 } 1843 } 1844 } else { 1845 getDeleteAllLinkTableRowsSqlWithInList(s); 1846 for (int i = 0; i < count; i++) { 1847 if (i != 0) s.append(","); 1848 driver.appendWhereParam(s, ourPkColumns[0]); 1849 } 1850 s.append(")"); 1851 String sql = s.toString(); 1852 ps = con.prepareStatement(sql); 1853 1854 int index = 1; 1855 for (int pos = blockStart; pos < blockEnd; pos++) { 1856 ((JdbcOID)graph.oids[pos]).setParams(ps, index++); 1857 } 1858 try { 1859 ps.execute(); 1860 } catch (Exception e) { 1861 throw mapException(e, 1862 "Batch delete link table rows failed: " + 1863 JdbcUtils.toString(e) + "\n" + 1864 "Field: " + fmd.getTypeQName() + "\n" + 1865 JdbcUtils.getPreparedStatementInfo(sql, ps)); 1866 } 1867 } 1868 return ps; 1869 } 1870 1871 private PreparedStatement deleteOneByOne(CharBuf s, Connection con, 1872 PreparedStatement ps, int blockStart, int blockEnd, 1873 DeletePacket graph) throws SQLException { 1874 String sql = getDeleteAllLinkTableRowsSql(s); 1875 ps = con.prepareStatement(sql); 1876 for (int pos = blockStart; pos < blockEnd; pos++) { 1877 ((JdbcOID)graph.oids[pos]).setParams(ps, 1); 1878 try { 1879 ps.execute(); 1880 } catch (Exception e) { 1881 throw mapException(e, 1882 "Delete link table rows failed: " + 1883 JdbcUtils.toString(e) + "\n" + 1884 "Field: " + fmd.getTypeQName() + "\n" + 1885 "Instance: " + graph.oids[pos].toSString() + "\n" + 1886 JdbcUtils.getPreparedStatementInfo(sql, ps)); 1887 } 1888 } 1889 return ps; 1890 } 1891 1892 1895 public SqlExp toIsEmptySqlExp(JdbcJDOQLCompiler comp, SelectExp root) { 1896 SelectExp se = new SelectExp(); 1897 se.table = linkTable; 1898 se.jdbcField = this; 1899 se.subSelectJoinExp = root.createJoinExp(root.table.pk, ourPkColumns, 1900 se); 1901 return new UnaryOpExp(new ExistsExp(se, true), UnaryOpExp.OP_NOT); 1902 } 1903 1904 1907 public SqlExp toContainsSqlExp(JdbcJDOQLCompiler comp, SelectExp root, 1908 Node args) { 1909 return toContainsSqlExp(valueColumns, fmd.elementTypeMetaData, comp, 1910 root, args); 1911 } 1912 1913 protected SqlExp toContainsSqlExp(JdbcColumn[] cols, ClassMetaData colsCmd, 1914 JdbcJDOQLCompiler comp, SelectExp root, Node args) { 1915 SelectExp se = new SelectExp(); 1916 se.table = linkTable; 1917 se.jdbcField = this; 1918 se.subSelectJoinExp = root.createJoinExp(root.table.pk, ourPkColumns, 1919 se); 1920 1921 if (args instanceof VarNodeIF) { 1922 VarNode v = ((VarNodeIF)args).getVarNode(); 1923 if (v.getCmd() == null) { 1924 SelectExp storeExtent = new SelectExp(); 1925 storeExtent.table = linkTable; 1926 storeExtent.var = v; 1927 v.setStoreExtent(storeExtent); 1928 v.setFieldExtent(se); 1929 v.setFmd(fmd); 1930 se.var = v; 1931 } else { 1932 SelectExp vse = (SelectExp)v.getStoreExtent(); 1933 se.addJoin(cols, vse.table.pk, vse); 1934 se.var = v; 1935 } 1936 } else { 1937 SqlExp left = JdbcColumn.toSqlExp(cols, se); 1938 if (colsCmd != null) { 1939 for (SqlExp e = left; e != null; e = e.next) { 1940 ((ColumnExp)e).cmd = colsCmd; 1941 } 1942 } 1943 SqlExp right = comp.getVisitor().toSqlExp(args, root, left, 0, null); 1944 se.whereExp = SqlExp.createBinaryOpExp(left, BinaryOpExp.EQUAL, 1945 right); 1946 } 1947 return new ExistsExp(se, true, (args instanceof VarNodeIF ? (VarNodeIF)args : null)); 1948 } 1949 1950 1953 private void processInverse(JdbcMetaDataBuilder mdb, JdoExtension e) { 1954 ClassMetaData ecmd = fmd.elementTypeMetaData; 1955 if (ecmd.storeClass == null) { 1956 throw BindingSupportImpl.getInstance().runtime("The inverse extension may only be used for " + 1957 "collections of PC instances stored by JDBC\n" + 1958 e.getContext()); 1959 } 1960 String fname = e.getString(); 1961 FieldMetaData f = ecmd.getFieldMetaData(fname); 1962 if (f.storeField == null) { 1963 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + "' is not persistent\n" + 1964 e.getContext()); 1965 } 1966 if (!(f.storeField instanceof JdbcLinkCollectionField)) { 1967 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + "' is not a collection or array mapped " + 1968 "using a link table\n" + e.getContext()); 1969 } 1970 inverse = (JdbcLinkCollectionField)f.storeField; 1971 if (f.elementTypeMetaData != fmd.classMetaData) { 1972 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + "' contains " + 1973 f.elementTypeMetaData + " and not our class\n" + 1974 e.getContext()); 1975 } 1976 if (inverse == this) { 1977 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + 1978 "' may not be in a many-to-many with itself\n" + 1979 e.getContext()); 1980 } 1981 inverse.inverse = this; 1982 readOnly = true; 1983 valuesAreOIDs = true; 1984 fmd.ordered = false; 1985 fmd.isManyToMany = true; 1986 fmd.isReadOnly = true; 1987 fmd.inverseFieldMetaData = inverse.fmd; 1988 inverse.fmd.isManyToMany = true; 1989 inverse.fmd.inverseFieldMetaData = fmd; 1990 syncWithInverse(mdb); 1991 } 1992 1993 1998 private void syncWithInverse(JdbcMetaDataBuilder mdb) { 1999 if (inverse == null) return; if (readOnly) { 2001 linkTable = inverse.linkTable; 2002 if (linkTable != null) { valueColumns = inverse.ourPkColumns; 2004 ourPkColumns = inverse.valueColumns; 2005 sequenceColumn = inverse.sequenceColumn; 2006 createInverseIndex(mdb); 2007 } 2008 fmd.managed = inverse.fmd.managed; 2009 } else { 2010 inverse.syncWithInverse(mdb); 2011 } 2012 } 2013 2014 2019 private void createInverseIndex(JdbcMetaDataBuilder mdb) { 2020 JdoExtension ext = JdoExtension.find(JdoExtensionKeys.INVERSE, 2021 getExtensions()); 2022 JdoExtension[] nested = ext.nested; 2023 2024 JdbcIndex idx = null; 2025 boolean doNotCreateIndex = false; 2026 2027 int n = nested == null ? 0 : nested.length; 2028 for (int i = 0; i < n; i++) { 2029 JdoExtension e = nested[i]; 2030 switch (e.key) { 2031 case JdoExtensionKeys.JDBC_INDEX: 2032 if (idx != null) { 2033 throw BindingSupportImpl.getInstance().runtime("Only one jdbc-index extension is allowed here\n" + 2034 e.getContext()); 2035 } 2036 if (e.isNoValue()) { 2037 doNotCreateIndex = true; 2038 break; 2039 } 2040 idx = new JdbcIndex(); 2041 idx.name = e.value; 2042 break; 2043 default: 2044 if (e.isJdbc()) { 2045 MetaDataBuilder.throwUnexpectedExtension(e); 2046 } 2047 } 2048 } 2049 2050 if (doNotCreateIndex) return; 2051 if (idx == null) idx = new JdbcIndex(); 2052 idx.setCols(ourPkColumns); 2053 2054 if (idx.name != null) { 2057 try { 2058 mdb.getNameGenerator().addIndexName(linkTable.name, 2059 idx.name); 2060 } catch (IllegalArgumentException x) { 2061 throw BindingSupportImpl.getInstance().runtime(x.getMessage(), 2062 x); 2063 } 2064 } 2065 2066 if (linkTable.indexes != null) { 2067 throw BindingSupportImpl.getInstance().internal("Link table already has index: " 2068 + linkTable + ", " + fmd.getTypeQName()); 2069 } 2070 linkTable.indexes = new JdbcIndex[]{idx}; 2071 } 2072 2073 2076 public void nameLinkTableIndexes(JdbcNameGenerator namegen) { 2077 if (readOnly) return; 2078 int n = linkTable == null ? 0 : linkTable.indexes == null ? 0 : linkTable.indexes.length; 2079 for (int i = 0; i < n; i++) { 2080 JdbcIndex idx = linkTable.indexes[i]; 2081 if (idx.name == null) { 2082 JdbcMetaDataBuilder.generateNameForIndex(namegen, 2083 linkTable.name, idx); 2084 } 2085 } 2086 } 2087 2088 2096 public String getFetchAllRowsSql(JdbcStorageManager sm) throws SQLException { 2097 SelectExp root = new SelectExp(); 2098 root.table = linkTable; 2099 SqlExp e = root.selectList = JdbcColumn.toSqlExp(ourPkColumns, root); 2100 for (; e.next != null; e = e.next) ; 2101 if (fmd.ordered) e = e.next = sequenceColumn.toSqlExp(root); 2102 e = e.next = JdbcColumn.toSqlExp(valueColumns, root); 2103 addFetchAllRowsKey(e, root); 2104 return sm.generateSql(root).toString(); 2105 } 2106 2107 2111 protected void addFetchAllRowsKey(SqlExp e, SelectExp se) { 2112 } 2113 2114 2119 public int readRow(ResultSet rs, LinkRow row) throws SQLException { 2120 row.owner = (JdbcGenericOID)fmd.classMetaData.createOID(false); 2121 row.owner.copyKeyFields(rs, 1); 2122 int pos = ourPkColumns.length + 1; 2123 if (fmd.ordered) { 2124 row.seq = ((Integer )sequenceColumn.get(rs, pos++)).intValue(); 2125 } 2126 if (valuesAreOIDs) { 2127 OID valueOid = fmd.elementTypeMetaData.createOID(false); 2128 ((JdbcOID)valueOid).copyKeyFields(rs, pos); 2129 row.value = valueOid; 2130 pos += valueColumns.length; 2131 } else { 2132 row.value = valueColumns[0].get(rs, pos++); 2133 } 2134 return pos; 2135 } 2136 2137 2141 public void writeRow(PreparedStatement ps, LinkRow row) 2142 throws SQLException { 2143 row.owner.setCmd(fmd.classMetaData); 2144 int pos = row.owner.setParams(ps, 1); 2145 if (fmd.ordered) sequenceColumn.set(ps, pos++, row.seq); 2146 if (valuesAreOIDs) { 2147 JdbcGenericOID v = (JdbcGenericOID)row.value; 2148 v.setCmd(fmd.classMetaData); 2149 v.setParams(ps, pos); 2150 } else { 2151 valueColumns[0].set(ps, pos, row.value); 2152 } 2153 } 2154 2155 2159 public static class LinkRow { 2160 2161 public JdbcGenericOID owner; 2162 public int seq; 2163 public Object key; 2164 public Object value; 2165 } 2166 2167} 2168 | Popular Tags |