1 2 12 package com.versant.core.jdbc; 13 14 import com.versant.core.common.Debug; 15 import com.versant.core.common.OID; 16 import com.versant.core.common.QueryResultContainer; 17 import com.versant.core.common.State; 18 import com.versant.core.metadata.*; 19 import com.versant.core.server.*; 20 import com.versant.core.jdbc.metadata.*; 21 import com.versant.core.jdbc.query.JdbcCompiledQuery; 22 import com.versant.core.jdbc.query.JdbcJDOQLCompiler; 23 import com.versant.core.jdbc.query.SqlStruct; 24 import com.versant.core.jdbc.sql.exp.SelectExp; 25 import com.versant.core.jdbc.sql.exp.SqlExp; 26 import com.versant.core.jdbc.sql.SqlDriver; 27 28 import com.versant.core.jdbc.ejbql.JdbcQueryResultEJBQL; 29 30 31 import java.math.BigDecimal ; 32 import java.math.BigInteger ; 33 import java.sql.*; 34 import java.util.*; 35 36 import com.versant.core.common.BindingSupportImpl; 37 import com.versant.core.storagemanager.RunningQuery; 38 import com.versant.core.storagemanager.ExecuteQueryReturn; 39 import com.versant.core.storagemanager.ApplicationContext; 40 import com.versant.core.jdo.QueryDetails; 41 42 45 public class JdbcQueryResult 46 implements RunningQuery, ExecuteQueryReturn { 47 48 private FetchInfo fetchInfo = new FetchInfo(); 49 50 protected PreparedStatement ps; 51 private ResultSet rs; 52 private Connection con; 53 54 private ClassMetaData cmd; 55 protected final JdbcStorageManager sm; 56 private FetchGroup fetchGroup; 57 private boolean includeSubclasses; 58 private boolean scrollable; 59 62 private int pos; 63 private int oidCols; 64 private JdbcOID lastOID; 65 66 public String sql; 67 68 72 private Map colHMap = new HashMap(); 73 76 protected JdbcCompiledQuery cq; 77 80 private JdbcJDOQLCompiler qCompiler; 81 82 private ModelMetaData jmd; 83 private Object [] params; 84 private boolean forUpdate; 85 private int nextCount; 86 87 private final Object [] singleResult = new Object [1]; 88 private boolean isCrossJoined; 89 90 93 private static final int STATUS_NOT_STARTED = 0; 94 97 private static final int STATUS_BUSY = 1; 98 101 private static final int STATUS_FINISHED = 2; 102 103 106 CachedQueryResult qRCache; 107 114 private int status; 115 119 private boolean isCacheble; 120 121 public JdbcQueryResult next; 122 public JdbcQueryResult prev; 123 124 public JdbcQueryResult(JdbcStorageManager sm, JdbcCompiledQuery cq, 125 Object [] params, boolean cachable) { 126 this.sm = sm; 127 this.cq = cq; 128 this.params = params; 129 isCacheble = cachable && cq.isCacheble(); 130 } 131 132 public void init(ClassMetaData cmd, boolean scrollable) { 133 this.cmd = cmd; 134 if (cmd != null) { 135 this.fetchGroup = cmd.fetchGroups[cq.getFetchGroupIndex()]; 136 this.oidCols = ((JdbcClass)cmd.storeClass).table.pkSimpleColumnCount; 137 isCrossJoined = cq.isCrossJoinAllowed() 138 && fetchGroup.crossJoinedCollectionField != null; 139 } else { 140 isCrossJoined = false; 141 } 142 143 this.jmd = sm.getJmd(); 144 this.includeSubclasses = cq.isIncludeSubclasses(); 145 this.scrollable = scrollable; 146 } 147 148 public RunningQuery getRunningQuery() { 149 return this; 150 } 151 152 public int getRelativeResultCount() { 153 return nextCount; 154 } 155 156 public void resetRelativeResultCount() { 157 nextCount = 0; 158 } 159 160 public Object [] getParams() { 161 return params; 162 } 163 164 public void setParams(Object [] params) { 165 this.params = params; 166 } 167 168 public FgDs getFgDs() { 169 return ((JdbcFetchGroup)fetchGroup.storeFetchGroup).getFgDs(includeSubclasses, false); 170 } 171 172 private OID getLastOID() { 173 return lastOID; 174 } 175 176 public void cancel() { 177 try { 178 ps.cancel(); 179 } catch (NullPointerException e) { 180 } catch (SQLException e) { 182 throw BindingSupportImpl.getInstance().invalidOperation(e.getMessage(), e); 183 } 184 } 185 186 public CompiledQuery getCompiledQuery() { 187 return cq; 188 } 189 190 public JdbcCompiledQuery getJdbcCompiledQuery() { 191 return cq; 192 } 193 194 public boolean isClosed() { 195 return ps == null; 196 } 197 198 201 public void close() { 202 if (colHMap != null) { 203 Collection col = colHMap.values(); 204 for (Iterator iterator = col.iterator(); iterator.hasNext();) { 205 ColFieldHolder holder = (ColFieldHolder)iterator.next(); 206 if (holder != null) { 207 holder.close(); 208 } 209 } 210 colHMap.clear(); 211 } 212 213 if (ps == null) return; 214 if (rs != null) { 215 try { 216 rs.close(); 217 } catch (SQLException e) { 218 } 220 rs = null; 221 } 222 if (isEJBQLHack()) { 223 224 ((JdbcQueryResultEJBQL)this).closeImp(); 225 226 } else { 227 try { 228 ps.close(); 229 ps = null; 230 } catch (SQLException e) { 231 throw sm.handleException(e); 232 } 233 } 234 235 setNonCacheble(); 236 status = STATUS_FINISHED; 237 238 qRCache = null; 239 params = null; 240 } 242 243 247 public boolean next(int skip) { 248 pos = 1; 249 252 try { 253 if (isCrossJoined) { 254 if (skip == 0 && fetchInfo.onNextRow) { 255 fetchInfo.onNextRow = false; 256 return true; 257 } 258 OID compareTo = null; 259 if (!fetchInfo.onNextRow && !fetchInfo.onValidRow) { 260 263 if (!rs.next()) { 264 fetchInfo.onValidRow = false; 265 return false; 266 } 267 fetchInfo.onValidRow = true; 268 if (skip == 0) { 269 return true; 270 } 271 } 272 273 276 compareTo = fetchInfo.nextOid; 277 if (compareTo == null) { 278 compareTo = getResultOID(); 279 pos = 1; 280 } 281 for (;skip >= 0;) { 282 285 if (!rs.next()) { 286 return false; 287 } 288 if (!getResultOID().equals(compareTo)) { 289 skip--; 291 } 292 compareTo = lastOID; 294 } 295 fetchInfo.nextOid = lastOID; 296 return true; 297 } else { 298 if (scrollable) { 299 return rs.relative(skip + 1); 300 } else { 301 for (int i = 0; i < skip; i++) if (!rs.next()) return false; 302 return rs.next(); 303 } 304 } 305 } catch (SQLException e) { 306 throw sm.handleException(e); 307 } 308 } 309 310 public boolean isRandomAccess() { 311 return scrollable; 312 } 313 314 public int getResultCount() { 315 if (isNotStarted()) { 316 updateCacheble(); 317 executeQueryImp(); 318 if (isCacheble()) { 319 qRCache = new CachedQueryResult(); 320 } 321 } 322 323 try { 324 if (!rs.last()) return 0; 325 return rs.getRow(); 326 } catch (SQLException e) { 327 throw sm.handleException(e); 328 } 329 } 330 331 public boolean absolute(int index) { 332 try { 333 pos = 1; 334 return rs.absolute(index + 1); 335 } catch (SQLException e) { 336 throw sm.handleException(e); 337 } 338 } 339 340 344 public OID getResultOID() { 345 pos = 1; 346 try { 347 lastOID = (JdbcOID)cmd.createOID(false); 348 if (cq.isSqlQuery()) { 349 if (cmd.pkFields == null) { 350 lastOID.copyKeyFields(rs, cq.getMappingInfo(rs).dsPkIndex); 351 } else { 352 lastOID.copyKeyFields(rs, cq.getMappingInfo(rs).fields, 353 cq.getMappingInfo(rs).pkIndexInFieldsArray); 354 } 355 } else { 356 lastOID.copyKeyFields(rs, pos); 357 pos += oidCols; 358 } 359 if (Debug.DEBUG) nextCount++; 360 return lastOID; 361 } catch (SQLException e) { 362 throw sm.handleException(e); 363 } 364 } 365 366 372 public State getResultState(boolean forUpdate, StateContainer container) { 373 try { 374 if (cq.isSqlQuery()) { 375 return getState(lastOID, cq.getMappingInfo(rs), rs); 376 } else { 377 MutableInt mutableInt = new MutableInt(); 378 State state = sm.createStateImp(rs, lastOID, 379 fetchGroup, forUpdate, pos, mutableInt, includeSubclasses, 380 container, cq.fgDs, !cq.isParColFetchEnabled(), 381 cq.isCrossJoinAllowed(), null); 382 if (cq.isCrossJoinAllowed()) { 384 FetchGroupField cjFGF = cq.fgDs.fg.crossJoinedCollectionField; 385 if (cjFGF != null) { 386 JdbcCollectionField colField = (JdbcCollectionField) cjFGF.fmd.storeField; 387 colField.fetchFrom(rs, lastOID, state, 388 cq.fgDs.fg.crossJoinedCollectionField, 389 forUpdate, container, 390 !cq.isParColFetchEnabled(), 391 mutableInt.value, fetchInfo, sm); 392 } 393 } 394 return state; 395 } 396 } catch (SQLException e) { 397 throw sm.handleException(e); 398 } 399 } 400 401 private static State getState(OID oid, JdbcCompiledQuery.MappingInfo mi, ResultSet rs) throws SQLException { 402 ClassMetaData cmd = mi.cmd; 403 if (mi.discrIndex != 0) { 404 Object classId = ((JdbcClass)cmd.storeClass).classIdCol.get(rs, mi.discrIndex); 405 if (rs.wasNull()) { 406 throw BindingSupportImpl.getInstance().objectNotFound("No row for " + 407 cmd.storeClass + " " + oid.toSString() + " OR " 408 + ((JdbcClass)cmd.storeClass).classIdCol.name + 409 " is null for row"); 410 } 411 cmd = ((JdbcClass)cmd.storeClass).findClass(classId); 412 if (cmd == null) { 413 throw BindingSupportImpl.getInstance().fatalDatastore( 414 "Row for OID " + oid.toSString() + 415 " is not in the heirachy starting at " + 416 mi.cmd.storeClass + 417 " (" + ((JdbcClass)mi.cmd.storeClass).classIdCol.name 418 + " for row is " + classId + ")"); 419 } 420 } 421 State state = cmd.createState(); 422 oid.resolve(state); 423 ((JdbcState)state).copyPass1Fields(rs, mi.fields); 424 return state; 425 } 426 427 431 public boolean addNextResult(ApplicationContext context, 432 QueryResultContainer results, int fetchAmount) { 433 try { 434 438 if (cq.isSqlQuery()) { 439 if (cq.isUnique()) { 440 int[] paramDir = cq.getParamDirection(); 441 Object [] outResult = new Object [cq.getOutParamCount()]; 442 int outCount = 0; 443 for (int i = 0; i < paramDir.length; i++) { 444 if (paramDir[i] == JdbcCompiledQuery.PARAM_OUT) { 445 outResult[outCount++] = ((CallableStatement)ps).getObject(i + 1); 446 } else if (paramDir[i] == JdbcCompiledQuery.PARAM_OUT_CURSOR) { 447 JdbcCompiledQuery.MappingInfo mi = cq.getMappingInfo(rs); 450 if (mi.isPkValid()) { 451 throw BindingSupportImpl.getInstance().unsupported(); 453 } else { 454 outResult[outCount++] = fetchAsObjects(mi); 455 } 456 } 457 } 458 results.addRow(outResult); 459 return true; 460 } else { 461 JdbcCompiledQuery.MappingInfo mi = cq.getMappingInfo(rs); 462 if (mi.isPkValid()) { 463 return fetchManagedTypes(context, fetchAmount, 464 cq.getFetchGroup(), results); 465 } else { 466 int colCount = mi.colCount; 467 do { 468 Object [] oa = new Object [colCount]; 469 for (int j = 0; j < colCount; j++) { 470 oa[j] = rs.getObject(j + 1); 471 472 } 473 results.addRow(oa); 474 } while (next(0)); 475 return true; 476 } 477 } 478 } 479 480 481 ProjectionQueryDecoder decoder = cq.getProjectionDecoder(); 482 489 if (decoder == null || decoder.isContainsThisOnly()) { 490 return fetchManagedTypes(context, fetchAmount, cq.getFetchGroup(), results); 491 } else { 492 if (decoder.containsThis()) { 493 return doContainsThis(fetchAmount, cq.getFetchGroup(), 494 decoder.getResultTypeArray(), decoder.getTypeCodes(), 495 decoder.getFmdArray(), 496 results); 497 } else { 498 return doResultOnly(fetchAmount, 499 decoder.getResultTypeArray(), 500 decoder.getFmdArray(), decoder.getTypeCodes(), 501 results); 502 } 503 } 504 } catch (SQLException e) { 505 throw sm.handleException(e); 506 } 507 } 508 509 private Object fetchAsObjects(JdbcCompiledQuery.MappingInfo mi) 510 throws SQLException { 511 int colCount = mi.colCount; 512 ArrayList rowData = new ArrayList(); 513 do { 514 Object [] oa = new Object [colCount]; 515 for (int j = 0; j < colCount; j++) { 516 oa[j] = rs.getObject(j + 1); 517 } 518 rowData.add(oa); 519 } while (next(0)); 520 return rowData; 521 } 522 523 526 private boolean fetchManagedTypes(ApplicationContext context, 527 int fetchAmount, FetchGroup fg, QueryResultContainer results) { 528 OID currentOid = null; 529 OID prevOid = null; 530 531 if (fetchAmount == -1) { 532 for(;;) { 534 currentOid = getResultOID(); 535 536 if (!currentOid.equals(prevOid)) { 538 sm.getState(context, currentOid, fg, this, results.container); 539 results.addRow(currentOid); 540 } else { 541 fetchInfo.onNextRow = false; 542 } 543 prevOid = currentOid; 544 if (fetchInfo.finished || !next(0)) break; 545 } 546 return true; 547 } else { 548 for (int i = 0; i < fetchAmount; i++) { 549 if (fetchInfo.onNextRow && fetchInfo.nextOid != null) { 550 currentOid = fetchInfo.nextOid; 551 fetchInfo.onNextRow = false; 552 fetchInfo.nextOid = null; 553 } else { 554 currentOid = getResultOID(); 555 } 556 557 if (!currentOid.equals(prevOid)) { 559 sm.getState(context, currentOid, fg, this, results.container); 560 results.addRow(currentOid); 561 } else { 562 fetchInfo.onNextRow = false; 563 } 564 565 if (fetchInfo.finished || !next(0)) return true; 567 prevOid = currentOid; 568 } 569 return false; 570 } 571 } 572 573 private boolean doContainsThis(int fetchAmount, 574 FetchGroup fg, int[] typeArray, int[] typeCodes, 575 Object [] fmdArray, 576 QueryResultContainer results) throws SQLException { 577 int rsIndex = 1 + cq.getSelectColumnCount(); 579 if (fetchAmount == -1) { 580 do { 581 sm.getState(getResultOID(), fg, results.container); 582 getDataImp(typeArray, fmdArray, typeCodes, rsIndex, results); 583 } while (next(0)); 584 return true; 585 } else { 586 for (int i = 0; i < fetchAmount; i++) { 587 sm.getState(getResultOID(), fg, results.container); 588 getDataImp(typeArray, fmdArray, typeCodes, rsIndex, results); 589 if (!next(0)) return true; 590 } 591 return false; 592 } 593 } 594 595 private boolean doResultOnly(int fetchAmount, int[] typeArray, 596 Object [] fmdArray, int[] typeCodes, 597 QueryResultContainer results) throws SQLException { 598 if (fetchAmount == -1) { 600 do { 601 getDataImp(typeArray, fmdArray, typeCodes, 1, results); 602 } while (next(0)); 603 return true; 604 } else { 605 for (int i = 0; i < fetchAmount; i++) { 606 getDataImp(typeArray, fmdArray, typeCodes, 1, results); 607 if (!next(0)) return true; 608 } 609 return false; 610 } 611 } 612 613 private void getDataImp(int[] typeArray, Object [] typeObjectArray, 614 int[] typeCodes, int currentRsIndex, 615 QueryResultContainer results) 616 throws SQLException { 617 618 Object [] resArray; 619 if (typeArray.length == 1) { 620 resArray = singleResult; 621 } else { 622 resArray = new Object [typeArray.length]; 623 } 624 625 for (int i = 0; i < typeArray.length; i++) { 626 int type = typeArray[i]; 627 switch (type) { 628 case ProjectionQueryDecoder.TYPE_THIS: resArray[i] = lastOID; 630 break; 631 case ProjectionQueryDecoder.TYPE_FIELD: currentRsIndex = getFieldData( 633 (FieldMetaData)typeObjectArray[i], rs, 634 currentRsIndex, resArray, i); 635 break; 636 case ProjectionQueryDecoder.TYPE_AGGRETATE: 638 currentRsIndex = getFieldData(typeCodes[i], rs, 639 currentRsIndex, resArray, i); 640 641 642 break; 643 case ProjectionQueryDecoder.TYPE_EXP: 644 currentRsIndex = getFieldData(typeCodes[i], rs, 645 currentRsIndex, resArray, i); 646 break; 647 case ProjectionQueryDecoder.TYPE_VAR: 648 ClassMetaData cmd = (ClassMetaData) typeObjectArray[i]; 649 JdbcOID oid = (JdbcOID) cmd.createOID(false); 650 if (oid.copyKeyFields(rs, currentRsIndex)) { 651 resArray[i] = oid; 652 } else { 653 resArray[i] = null; 654 } 655 currentRsIndex += ((JdbcClass)cmd.storeClass).table.pk.length; 656 break; 657 default: 658 throw BindingSupportImpl.getInstance().internal(""); 659 } 660 } 661 662 if (typeArray.length == 1) { 663 results.addRow(resArray[0]); 664 } else { 665 results.addRow(resArray); 666 } 667 } 668 669 private int getFieldData(int typeCode, ResultSet rs, int rsIndex, 670 Object [] dataRow, int dataIndex) throws SQLException { 671 switch (typeCode) { 672 case MDStatics.BYTEW: 673 dataRow[dataIndex] = new Byte (rs.getByte(rsIndex)); 674 break; 675 case MDStatics.SHORTW: 676 dataRow[dataIndex] = new Short (rs.getShort(rsIndex)); 677 break; 678 case MDStatics.INTW: 679 dataRow[dataIndex] = new Integer (rs.getInt(rsIndex)); 680 break; 681 case MDStatics.LONGW: 682 dataRow[dataIndex] = new Long (rs.getLong(rsIndex)); 683 break; 684 case MDStatics.FLOATW: 685 dataRow[dataIndex] = new Float (rs.getFloat(rsIndex)); 686 break; 687 case MDStatics.DOUBLEW: 688 dataRow[dataIndex] = new Double (rs.getDouble(rsIndex)); 689 break; 690 case MDStatics.STRING: 691 dataRow[dataIndex] = rs.getString(rsIndex); 692 break; 693 case MDStatics.BIGDECIMAL: 694 dataRow[dataIndex] = new BigDecimal (rs.getDouble(rsIndex)); 695 break; 696 case MDStatics.BIGINTEGER: 697 dataRow[dataIndex] = new BigInteger (rs.getString(rsIndex)); 698 break; 699 default: 700 throw BindingSupportImpl.getInstance().internal( 701 "Unhandled type '" + typeCode + "'"); 702 } 703 return rsIndex + 1; 704 } 705 706 public int getFieldData(FieldMetaData fmd, ResultSet rs, int firstCol, 707 Object [] dataRow, int dataIndex) throws SQLException { 708 JdbcField f = (JdbcField)fmd.storeField; 709 if (f instanceof JdbcSimpleField) { 710 JdbcColumn c = ((JdbcSimpleField)f).col; 711 if (Debug.DEBUG) { 712 if (!cq.isProjectionQuery() && !c.name.toUpperCase().equals( 713 rs.getMetaData().getColumnName(firstCol).toUpperCase())) { 714 throw BindingSupportImpl.getInstance().internal( 715 "Reading the wrong column: \nrs field = " 716 + rs.getMetaData().getColumnName(firstCol) + "\nmetaData field = " + c.name); 717 } 718 } 719 if (c.converter != null) { 720 dataRow[dataIndex] = c.converter.get(rs, firstCol++, c ); 721 } else { 722 dataRow[dataIndex] = JdbcUtils.get(rs, firstCol++, c.javaTypeCode, 723 c.scale ); 724 if (rs.wasNull()) { 725 dataRow[dataIndex] = null; 726 } 727 } 728 } else if (f instanceof JdbcRefField) { 729 JdbcRefField rf = (JdbcRefField)f; 730 JdbcOID oid = (JdbcOID)rf.targetClass.createOID(false); 731 if (oid.copyKeyFields(rs, firstCol)) { 732 dataRow[dataIndex] = oid; 733 } else { 734 dataRow[dataIndex] = null; 735 } 736 firstCol += rf.cols.length; 737 } else if (f instanceof JdbcPolyRefField) { 738 dataRow[dataIndex] = JdbcGenericState.getPolyRefOID(f, rs, firstCol); 739 firstCol += ((JdbcPolyRefField)f).cols.length; 740 } else { 741 throw BindingSupportImpl.getInstance().internal("not implemented"); 742 } 743 return firstCol; 744 } 745 746 public void doParallelFetch(boolean forUpdate, StateContainer container) { 747 this.forUpdate = forUpdate; 748 try { 749 if (cq.isParColFetchEnabled()) { 750 processParallelFetch(cq.fgDs.getJoinStruct(), 1, true, null, container); 751 } 752 } catch (Exception e) { 753 throw sm.handleException(e); 754 } 755 } 756 757 private JdbcJDOQLCompiler getQComp() { 758 if (qCompiler == null) { 759 qCompiler = new JdbcJDOQLCompiler(sm); 760 } else { 761 qCompiler.reinit(); 762 } 763 return qCompiler; 764 } 765 766 769 private void exectureQ(SqlStruct sqlStruct, 770 ColFieldHolder colHolder) throws SQLException { 771 sqlStruct.updateSql(sm.getSqlDriver(), params, forUpdate, false); 772 String sql = sqlStruct.getSql(); 773 PreparedStatement p2Ps = con.prepareStatement(sql); 774 sqlStruct.setParamsOnPS(jmd, sm.getSqlDriver(), p2Ps, params, sql); 775 colHolder.ps = p2Ps; 776 colHolder.rs = p2Ps.executeQuery(); 777 } 778 779 private SqlStruct createSqlStruct(ColFieldHolder colHolder) { 780 final SqlStruct sqlStruct = new SqlStruct(); 781 sqlStruct.jdoqlFilter = "PQ: " + cq.getQueryDetails().getFilter(); 782 783 JdbcJDOQLCompiler qComp = getQComp(); 784 SelectExp root = (SelectExp)qComp.compileParallelFetch( 785 cq.getQueryDetails()); 786 SelectExp se = colHolder.createSE(sm, root); 787 788 SqlExp e = JdbcColumn.toSqlExp(((JdbcClass)cmd.storeClass).table.pk, root, 790 root.selectList); 791 root.selectList = e; 792 793 root.appendOrderByExp(se.orderByList); 794 795 JdbcJDOQLCompiler.doFinalSql(sqlStruct, root, sm.getSqlDriver()); 796 JdbcJDOQLCompiler.compileParams(qComp.getQParser(), sqlStruct); 797 return sqlStruct; 798 } 799 800 803 private void processParallelFetch(JoinStructure rootJs, int level, boolean valueJoin, 804 ColFieldHolder parent, StateContainer container) throws SQLException { 805 if (rootJs == null) return; 806 if (!rootJs.rootJoinStructure) throw BindingSupportImpl.getInstance().internal(""); 807 rootJs.finish(); 808 809 List l = rootJs.colJoinStructs; 810 if (l == null) return; 811 for (int i = 0; i < l.size(); i++) { 812 JoinStructure js2 = (JoinStructure)l.get(i); 813 ColFHKey key = new ColFHKey(level, valueJoin, js2); 814 ColFieldHolder colFHolder = (ColFieldHolder)colHMap.get(key); 815 if (colFHolder == null) { 816 colFHolder = new ColFieldHolder(parent, valueJoin, js2); 817 colHMap.put(key, colFHolder); 818 819 831 832 if (level == 1 && js2.parent == rootJs 833 && js2.fgField == rootJs.fetchGroup.crossJoinedCollectionField 834 && cq.isCrossJoinAllowed()) { 835 colFHolder.valueJs = cq.fgDs.valueJs; 837 colFHolder.returnState = JdbcCollectionField.STATUS_VALID_ROWS 839 + JdbcCollectionField.STATUS_DATA_ADDED; 840 colFHolder.crossJoinedField = true; 841 } else { 842 SqlStruct sqlStr = cq.get(key); 843 if (sqlStr == null) { 844 sqlStr = createSqlStruct(colFHolder); 845 exectureQ(sqlStr, colFHolder); 846 cq.add(key, sqlStr); 847 } else { 848 synchronized (sqlStr) { 849 exectureQ(sqlStr, colFHolder); 850 } 851 } 852 } 853 } 854 855 if ((colFHolder.returnState & JdbcCollectionField.STATUS_CLOSED) 856 == JdbcCollectionField.STATUS_CLOSED) { 857 continue; 859 } 860 861 if (!colFHolder.crossJoinedField) { 863 colFHolder.returnState = ((JdbcCollectionField)js2.fgField.fmd.storeField). 864 fetchWithFilter(sm, container, js2.fgField, 865 colFHolder.rs, forUpdate, getLastOID(), 866 colFHolder.lastOIDs, cmd, colFHolder); 867 } 868 869 if ((colFHolder.returnState & JdbcCollectionField.STATUS_VALID_ROWS) 870 != JdbcCollectionField.STATUS_VALID_ROWS) { 871 continue; 873 } 874 875 if ((colFHolder.returnState & JdbcCollectionField.STATUS_DATA_ADDED) 876 != JdbcCollectionField.STATUS_DATA_ADDED) { 877 continue; 879 } 880 881 if (js2.fgField.nextFetchGroup != null) { 883 processParallelFetch(colFHolder.valueJs, level + 1, true, colFHolder, container); 885 } 886 887 if (js2.fgField.nextKeyFetchGroup != null) { 889 processParallelFetch(colFHolder.keyJs, level + 1, false, colFHolder, container); 891 } 892 } 893 } 894 895 898 public boolean isCachedResultsOk() { 899 return isCacheble && status == STATUS_NOT_STARTED; 900 } 901 902 public void setQResult(QueryResultContainer qContainer) { 903 if (Debug.DEBUG) { 904 if (status != STATUS_NOT_STARTED) { 905 throw BindingSupportImpl.getInstance().internal( 906 "query already started"); 907 } 908 } 909 status = STATUS_BUSY; 910 if (cq.isRandomAccess()) { 911 if (!absolute(0)) { 912 status = STATUS_FINISHED; 913 qContainer.qFinished = true; 914 } 915 } else { 916 if (!next(0)) { 917 status = STATUS_FINISHED; 918 qContainer.qFinished = true; 919 } 920 } 921 } 922 923 public boolean isNotStarted() { 924 return status == STATUS_NOT_STARTED; 925 } 926 927 public void getAbsolute(ApplicationContext context, 928 QueryResultContainer qContainer, int index, int fetchAmount) { 929 if (isNotStarted()) { 930 executeQueryImp(); 931 setQResult(qContainer); 932 } 933 934 resetRelativeResultCount(); 935 if (Debug.DEBUG) { 936 if (!isRandomAccess()) { 937 throw BindingSupportImpl.getInstance().internal("getAbsolute may only " + 938 "be called on randomAccess queries"); 939 } 940 } 941 if (absolute(index)) { 942 if (addNextResult(context, qContainer, fetchAmount)) { 943 status = STATUS_FINISHED; 944 } 945 doParallelFetch(forUpdate, qContainer.container); 946 } 947 948 if (status == STATUS_FINISHED) { 949 qContainer.qFinished = true; 950 } 951 } 952 953 957 public boolean nextBatch(ApplicationContext context, int skipAmount, 958 QueryResultContainer qContainer) { 959 prepare(qContainer); 960 updateCacheble(); 961 962 963 if (skipAmount != 0) { 965 setNonCacheble(); 966 if (!next(skipAmount - 1)) { 967 status = STATUS_FINISHED; 968 } 969 } 970 971 if (status != STATUS_FINISHED) { 972 if (addNextResult(context, qContainer, cq.getQueryResultBatchSize())) { 973 status = STATUS_FINISHED; 974 } 975 976 if (qRCache != null) { 977 qContainer.addResultsTo(qRCache, 978 cq.isCopyResultsForCache()); 979 } 980 } 981 doParallelFetch(forUpdate, qContainer.container); 982 if (status == STATUS_FINISHED) { 983 qContainer.qFinished = true; 984 } 985 return status == STATUS_FINISHED; 986 } 987 988 private void prepare(QueryResultContainer qContainer) { 989 if (isNotStarted()) { 990 updateCacheble(); 991 executeQueryImp(); 992 setQResult(qContainer); 993 if (isCacheble()) { 994 qRCache = new CachedQueryResult(); 995 } 996 } else { 997 resetRelativeResultCount(); 998 } 999 } 1000 1001 1004 public void updateCacheble() { 1005 if (isCacheble) { 1006 if (sm.isActive() && !sm.isOptimistic() || sm.isFlushed() 1007 || !sm.getCache().isQueryCacheEnabled()) { 1008 setNonCacheble(); 1009 return; 1010 } 1011 } 1012 } 1013 1014 public boolean isFinished() { 1015 return status == STATUS_FINISHED; 1016 } 1017 1018 public boolean isCacheble() { 1019 return isCacheble; 1020 } 1021 1022 public QueryDetails getQueryDetails() { 1023 return cq.getQueryDetails(); 1024 } 1025 1026 private void executeQueryImp() { 1027 executePrepare(sm.isForUpdate(), sm.getSqlDriver()); 1028 executeActual(); 1029 } 1030 1031 private void executePrepare(boolean forUpdate, SqlDriver sqlDriver) { 1032 JdbcCompiledQuery cq = getJdbcCompiledQuery(); 1033 ClassMetaData cmd = cq.getCmd(); 1034 boolean randomAccess = cq.isRandomAccess(); 1035 if (randomAccess && !sqlDriver.isScrollableResultSetSupported()) { 1036 throw BindingSupportImpl.getInstance().datastore("Random access not supported for " + 1037 sqlDriver.getName() + " using JDBC driver " + 1038 sm.getJdbcConnectionSource().getDriverName()); 1039 } 1040 init(cmd, randomAccess); 1041 Object [] params = getParams(); 1042 boolean ok = false; 1043 try { 1044 con = sm.con(); 1045 if (isEJBQLHack()) { 1046 1047 ((JdbcQueryResultEJBQL)this).executePrepareHack(params); 1048 1049 } else if (!cq.isSqlQuery()) { 1050 SqlStruct sqlStr = cq.getSqlStruct(); 1052 synchronized (sqlStr) { 1053 sqlStr.updateSql(sqlDriver, params, forUpdate, 1054 false); 1055 String sql = sql = cq.getSql(); 1056 if (randomAccess) { 1057 ps = con.prepareStatement(sql, 1058 ResultSet.TYPE_SCROLL_INSENSITIVE, 1059 ResultSet.CONCUR_READ_ONLY); 1060 } else { 1061 ps = con.prepareStatement(sql); 1062 } 1063 sqlStr.setParamsOnPS(jmd, sqlDriver, ps, 1064 params, sql); 1065 } 1066 1067 } else if (cq.isStoredProc()) { 1068 CallableStatement cs = con.prepareCall( 1069 cq.getQueryDetails().getFilter()); 1070 ps = cs; 1071 int[] sqlTypes = cq.getSqlTypes(); 1072 int[] paramDir = cq.getParamDirection(); 1073 1074 final int count = sqlTypes.length; 1075 for (int i = 0; i < count; i++) { 1076 if (paramDir[i] == JdbcCompiledQuery.PARAM_IN) { 1077 cs.setObject(i + 1, params[i], sqlTypes[i]); 1078 } else if (paramDir[i] == JdbcCompiledQuery.PARAM_OUT) { 1079 cs.registerOutParameter(i + 1, sqlTypes[i]); 1080 } else if (paramDir[i] == JdbcCompiledQuery.PARAM_OUT_CURSOR) { 1081 cs.registerOutParameter(i + 1, -10); 1082 } 1083 } 1084 1085 } else if (cq.isDirectSql()) { 1086 ps = con.prepareStatement(cq.getQueryDetails().getFilter()); 1087 int[] sqlTypes = cq.getSqlTypes(); 1088 final int count = sqlTypes.length; 1089 for (int i = 0; i < count; i++) { 1090 ps.setObject(i + 1, params[i], sqlTypes[i]); 1091 } 1092 } else { 1093 throw BindingSupportImpl.getInstance().internal("Undefined query type"); 1094 } 1095 1096 int maxRows = cq.getMaxRows(); 1097 ps.setMaxRows(maxRows < 0 ? 0 : maxRows); 1098 ok = true; 1099 } catch (SQLException x) { 1100 throw sm.handleException(x); 1101 } finally { 1102 if (!ok) { 1103 try { 1104 close(); 1105 } catch (Exception x) { 1106 } 1108 } 1109 } 1110 } 1111 1112 private void executeActual() { 1113 JdbcCompiledQuery cq = getJdbcCompiledQuery(); 1114 1115 int maxRows = cq.getMaxRows(); 1116 1117 boolean ok = false; 1118 try { 1119 if (sm.getSqlDriver().isFetchSizeSupported()) { 1120 int fetchSize = cq.getQueryResultBatchSize(); 1121 if (maxRows > 0 && fetchSize > maxRows) fetchSize = maxRows; 1122 if (fetchSize > 0) ps.setFetchSize(fetchSize); 1123 } 1124 1125 try { 1126 if (isEJBQLHack()) { 1127 1128 ((JdbcQueryResultEJBQL)this).executeActualHack(); 1129 1130 } else if (cq.isSqlQuery()) { 1131 if (cq.isStoredProc() && sm.getSqlDriver().isOracleStoreProcs()) { 1132 ps.executeUpdate(); 1133 int[] paramDir = cq.getParamDirection(); 1134 boolean cursorSet = false; 1135 QueryDetails queryDetails = cq.getQueryDetails(); 1136 final int count = queryDetails.getParamCount(); 1137 for (int i = 0; i < count; i++) { 1138 if (paramDir[i] == JdbcCompiledQuery.PARAM_OUT_CURSOR) { 1139 if (cursorSet) { 1140 throw BindingSupportImpl.getInstance().invalidOperation( 1141 "Query may have only one OUT parameter"); 1142 } 1143 rs = (ResultSet)((CallableStatement) 1144 ps).getObject(i + 1); 1145 cq.getMappingInfo(rs); 1146 cursorSet = true; 1147 } 1148 } 1149 if (!cursorSet) { 1150 rs = (ResultSet)((CallableStatement) 1151 ps).getObject(count + 1); 1152 cq.getMappingInfo(rs); 1153 } 1154 } else { 1155 rs = ps.executeQuery(); 1156 cq.getMappingInfo(rs); 1157 } 1158 1161 if (!cq.getMappingInfo(rs).isPkValid() 1162 && cq.getQueryDetails().getCandidateClass() != null) { 1163 throw BindingSupportImpl.getInstance().invalidOperation( 1164 "Candidate class '" 1165 + cq.getQueryDetails().getCandidateClass().getName() 1166 + "' was specified, " 1167 + "but the ResultSet does not contain any/all of the pk columns."); 1168 } 1169 } else { 1170 rs = ps.executeQuery(); 1171 } 1172 } catch (SQLException e) { 1173 throw sm.handleException("Query failed: " + JdbcUtils.toString( 1174 e) + "\n" + 1175 JdbcUtils.getPreparedStatementInfo(sql, ps), 1176 e); 1177 } 1178 1179 ok = true; 1180 } catch (SQLException e) { 1181 sm.handleException(e); 1182 } finally { 1183 if (!ok) { 1184 try { 1185 close(); 1186 } catch (Exception x) { 1187 } 1189 } 1190 } 1191 } 1192 1193 1197 public void setNonCacheble() { 1198 isCacheble = false; 1199 qRCache = null; 1200 } 1201 1202 1205 public boolean isEJBQLHack() { 1206 return false; 1207 } 1208 1209 public void getAllResults(ApplicationContext context, 1210 QueryResultContainer container, boolean forUpdate) { 1211 try { 1212 executeQueryImp(); 1213 resetRelativeResultCount(); 1214 1215 if (next(0)) { 1216 addNextResult(context, container, -1); 1217 } 1218 doParallelFetch(forUpdate, container.container); 1219 } finally { 1220 close(); 1221 } 1222 } 1223 1224 1227 public class ColFHKey { 1228 1229 private int level; 1230 private boolean valueJoin; 1231 private JoinStructure js; 1232 1233 public ColFHKey(int level, boolean valueJoin, JoinStructure js) { 1234 this.level = level; 1235 this.valueJoin = valueJoin; 1236 this.js = js; 1237 } 1238 1239 public boolean equals(Object o) { 1240 if (this == o) return true; 1241 if (!(o instanceof ColFHKey)) return false; 1242 1243 final ColFHKey colFHKey = (ColFHKey)o; 1244 1245 if (level != colFHKey.level) return false; 1246 if (valueJoin != colFHKey.valueJoin) return false; 1247 if (!js.equals(colFHKey.js)) return false; 1248 1249 return true; 1250 } 1251 1252 public int hashCode() { 1253 int result; 1254 result = level; 1255 result = 29 * result + (valueJoin ? 1 : 0); 1256 result = 29 * result + js.hashCode(); 1257 return result; 1258 } 1259 1260 public void dump() { 1261 System.out.println("\n\n --JdbcQueryResult$ColFHKey.dump"); 1262 System.out.println("level = " + level); 1263 System.out.println("valueJoin = " + valueJoin); 1264 System.out.println("js = " + js); 1265 } 1266 1267 } 1268} 1269 1270 | Popular Tags |