1 2 12 package com.versant.core.jdo; 13 14 import com.versant.core.common.Debug; 15 import com.versant.core.metadata.ClassMetaData; 16 import com.versant.core.metadata.FetchGroup; 17 import com.versant.core.metadata.MDStatics; 18 import com.versant.core.metadata.parser.JdoExtension; 19 import com.versant.core.metadata.parser.JdoExtensionKeys; 20 import com.versant.core.metadata.parser.JdoQuery; 21 import com.versant.core.util.CharBuf; 22 import com.versant.core.util.IntArray; 23 24 import javax.jdo.Extent; 25 import java.io.Externalizable ; 26 import java.io.IOException ; 27 import java.io.ObjectInput ; 28 import java.io.ObjectOutput ; 29 import java.util.Collection ; 30 31 import com.versant.core.common.BindingSupportImpl; 32 33 36 public final class QueryDetails 37 implements Externalizable , ParamDeclarationParser.Handler { 38 39 private static final int DEFAULT_BATCH_SIZE = 50; 40 41 public static final int LANGUAGE_JDOQL = 1; 42 public static final int LANGUAGE_SQL = 2; 43 public static final int LANGUAGE_OQL = 3; 44 public static final int LANGUAGE_EJBQL = 4; 45 46 public static final int NOT_SET = 0; 47 public static final int FALSE = 1; 48 public static final int TRUE = 2; 49 50 private int language; 51 private Class candidateClass; 52 private boolean subClasses = true; 53 private transient Collection col; 54 private String filter; 55 private String imports; 56 private String variables; 57 private String ordering; 58 private String result; 59 private String grouping; 60 private int unique; 61 private boolean ignoreCache; 62 private boolean useIgnoreCacheFromPM; 63 64 private int paramCount; 65 private String [] paramTypes; 66 private String [] paramNames; 67 private int optionsParamIndex = -1; 70 71 private int fetchGroupIndex; 72 private boolean randomAccess; 73 private boolean countOnSize; 74 private boolean bounded; 75 76 private int resultBatchSize = -1; 77 private int maxResultCount = -1; 78 79 private int[] extraEvictClasses; private int cacheable; 82 public QueryDetails() { 83 } 84 85 88 public QueryDetails(ClassMetaData cmd, JdoQuery q) { 89 if (q.sql != null) { 90 language = LANGUAGE_SQL; 91 filter = q.sql; 92 } else { 93 language = LANGUAGE_JDOQL; 94 filter = q.filter; 95 } 96 candidateClass = cmd.cls; 97 subClasses = q.includeSubclasses != MDStatics.FALSE; 98 if (useIgnoreCacheFromPM = q.ignoreCache == MDStatics.NOT_SET) { 99 ignoreCache = false; 100 } else { 101 ignoreCache = q.ignoreCache == MDStatics.TRUE; 102 } 103 imports = q.imports; 104 variables = q.variables; 105 ordering = q.ordering; 106 result = q.result; 107 grouping = q.grouping; 108 unique = q.unique; 109 if (q.extensions != null) { 110 for (int i = 0; i < q.extensions.length; i++) { 111 JdoExtension e = q.extensions[i]; 112 switch (e.key) { 113 case JdoExtensionKeys.FETCH_GROUP: 114 FetchGroup fg = cmd.getFetchGroup(e.getString()); 115 if (fg == null) { 116 throw BindingSupportImpl.getInstance().runtime("Query fetch group " + 117 "not found on " + cmd.qname + ": " + e + 118 "\n" + e.getContext()); 119 } 120 fetchGroupIndex = fg.index; 121 break; 122 case JdoExtensionKeys.RANDOM_ACCESS: 123 randomAccess = e.getBoolean(); 124 break; 125 case JdoExtensionKeys.COUNT_STAR_ON_SIZE: 126 countOnSize = e.getBoolean(); 127 break; 128 case JdoExtensionKeys.MAX_ROWS: 129 maxResultCount = e.getInt(); 130 break; 131 case JdoExtensionKeys.FETCH_SIZE: 132 resultBatchSize = e.getInt(); 133 break; 134 case JdoExtensionKeys.BOUNDED: 135 bounded = e.getBoolean(); 136 break; 137 case JdoExtensionKeys.EVICTION_CLASSES: 138 extraEvictClasses = processEvictionClassesExt(cmd, e); 139 break; 140 case JdoExtensionKeys.CACHEABLE: 141 setCacheable(e.getBoolean()); 142 break; 143 case JdoExtension.QUERY_PARAM_VALUES: 144 break; 146 default: 147 throw createExtNotAllowed(e); 148 } 149 } 150 } 151 try { 152 declareParameters(q.parameters); 153 } catch (RuntimeException e) { 154 if( BindingSupportImpl.getInstance().isOwnException(e) ) 155 { 156 throw BindingSupportImpl.getInstance().runtime("Invalid parameter declaration: " + 157 e + "\n" + q.getContext(), e); 158 } 159 else 160 { 161 throw e; 162 } 163 } 164 } 165 166 public int getLanguage() { 167 return language; 168 } 169 170 public void setLanguage(int language) { 171 this.language = language; 172 } 173 174 public String getLanguageStr() { 175 switch (language) { 176 case LANGUAGE_JDOQL: return "JDOQL"; 177 case LANGUAGE_SQL: return "SQL"; 178 case LANGUAGE_OQL: return "OQL"; 179 case LANGUAGE_EJBQL: return "EJBQL"; 180 } 181 return "UNKNOWN(" + language + ")"; 182 } 183 184 public int getUnique() { 185 return unique; 186 } 187 188 public void setUnique(boolean unique) { 189 this.unique = unique ? TRUE : FALSE; 190 } 191 192 public String getGrouping() { 193 return grouping; 194 } 195 196 public void setGrouping(String grouping) { 197 this.grouping = grouping; 198 } 199 200 public String getResult() { 201 return result; 202 } 203 204 public void setResult(String result) { 205 this.result = result; 206 } 207 208 private RuntimeException createExtNotAllowed(JdoExtension e) { 209 return BindingSupportImpl.getInstance().runtime("Extension not allowed here: " + 210 e + "\n" + e.getContext()); 211 } 212 213 private int[] processEvictionClassesExt(ClassMetaData cmd, 214 JdoExtension ext) { 215 boolean includeSubclasses = ext.getBoolean(); 216 if (ext.nested == null) return null; 217 IntArray ans = new IntArray(); 218 for (int i = 0; i < ext.nested.length; i++) { 219 JdoExtension e = ext.nested[i]; 220 if (e.key != JdoExtensionKeys.CLASS) throw createExtNotAllowed(e); 221 String name = e.getString(); 222 ClassMetaData target = cmd.jmd.getClassMetaData(cmd, name); 223 if (target == null) { 224 throw BindingSupportImpl.getInstance().runtime("Class does not exist or " + 225 "is not persistent: " + e + "\n" + e.getContext()); 226 } 227 if (includeSubclasses) { 228 addIndexesForHeirachy(target, ans); 229 } else { 230 ans.add(target.index); 231 } 232 } 233 return ans.toArray(); 234 } 235 236 private void addIndexesForHeirachy(ClassMetaData root, IntArray ans) { 237 ans.add(root.index); 238 if (root.pcSubclasses == null) return; 239 for (int i = 0; i < root.pcSubclasses.length; i++) { 240 addIndexesForHeirachy(root.pcSubclasses[i], ans); 241 } 242 } 243 244 public boolean includeSubClasses() { 245 return subClasses; 246 } 247 248 public void setSubClasses(boolean subClasses) { 249 this.subClasses = subClasses; 250 } 251 252 public QueryDetails(QueryDetails qParams) { 253 this.fillFrom(qParams); 254 } 255 256 public int getResultBatchSize() { 257 return resultBatchSize; 258 } 259 260 268 public boolean prefetchAll() { 269 return maxResultCount == resultBatchSize; 270 } 271 272 public void setResultBatchSize(int value) { 273 if (value <= 0) { 274 throw BindingSupportImpl.getInstance().invalidOperation( 275 "The batch size must be greater than zero"); 276 } 277 this.resultBatchSize = value; 278 } 279 280 public int getMaxResultCount() { 281 return maxResultCount; 282 } 283 284 290 public void setMaxResultCount(int value) { 291 if (value < 0) { 292 throw BindingSupportImpl.getInstance().invalidOperation( 293 "The query max result count must be greater or equal to zero"); 294 } 295 this.maxResultCount = value; 296 } 297 298 302 public void updateCounts() { 303 if (resultBatchSize == -1) { 304 if (maxResultCount == -1) { 305 resultBatchSize = DEFAULT_BATCH_SIZE; 307 } else { 308 resultBatchSize = maxResultCount; 311 } 312 } else { 313 if (maxResultCount != -1 && maxResultCount < resultBatchSize) { 317 resultBatchSize = maxResultCount; 318 } 319 } 320 } 321 322 326 public static boolean enableParallelCollectionFetch(QueryDetails qp, 327 FetchGroup fg) { 328 return qp.bounded && !qp.randomAccess && fg.canUseParallelFetch(); 329 } 330 331 public boolean isBounded() { 332 return bounded; 333 } 334 335 public void setBounded(boolean value) { 336 bounded = value; 337 } 338 339 public Class getCandidateClass() { 340 return candidateClass; 341 } 342 343 public void setCandidateClass(Class candidateClass) { 344 this.candidateClass = candidateClass; 345 } 346 347 public void setExtent(Extent extent) { 348 if (Debug.DEBUG) { 349 if (extent == null) { 350 throw BindingSupportImpl.getInstance().internal( 351 "Setting extent to null is not supported"); 352 } 353 } 354 candidateClass = extent.getCandidateClass(); 355 subClasses = extent.hasSubclasses(); 356 col = null; 357 } 358 359 public Collection getCol() { 360 return col; 361 } 362 363 public void setCol(Collection col) { 364 this.col = col; 365 subClasses = true; 366 } 367 368 public String getFilter() { 369 return filter; 370 } 371 372 public void setFilter(String filter) { 373 this.filter = checkString(filter); 374 } 375 376 private boolean checkString(String lString, String oString) { 377 if (lString == null) { 378 return oString == null; 379 } 380 return lString.equals(oString); 381 } 382 383 private final String checkString(String val) { 384 if (val == null || val.equals("")) { 385 return null; 386 } 387 return val; 388 } 389 390 public String getImports() { 391 return imports; 392 } 393 394 public void setImports(String imports) { 395 this.imports = checkString(imports); 396 } 397 398 public void declareParameters(String params) { 399 optionsParamIndex = -1; 400 paramTypes = null; 401 paramNames = null; 402 paramCount = 0; 403 ParamDeclarationParser.parse(checkString(params), this); 404 } 405 406 public int hashCode() { 407 int result; 408 result = (candidateClass != null ? candidateClass.getName().hashCode() : 0); 409 result = 29 * result + (filter != null ? filter.hashCode() : 0); 410 result = 29 * result + (ordering != null ? ordering.hashCode() : 0); 411 return result; 412 } 413 414 public boolean equals(Object o) { 415 if (o == this) return true; 416 if (o instanceof QueryDetails) { 417 QueryDetails other = (QueryDetails)o; 418 return randomAccess == other.randomAccess 420 && countOnSize == other.countOnSize 421 && bounded == other.bounded 422 && fetchGroupIndex == other.fetchGroupIndex 423 && subClasses == other.subClasses 424 && maxResultCount == other.maxResultCount 425 && resultBatchSize == other.resultBatchSize 426 && ignoreCache == other.ignoreCache 427 && unique == other.unique 428 && language == other.language 429 && cacheable == other.cacheable 430 && checkString(filter, other.filter) 431 && checkString(result, other.result) 432 && checkString(grouping, other.grouping) 433 && checkCandidate(other) 434 && checkString(ordering, other.ordering) 435 && checkExtraEvictClasses(other); 436 } else { 437 return false; 438 } 439 } 440 441 private boolean checkExtraEvictClasses(QueryDetails other) { 442 if (extraEvictClasses != null) { 443 int[] a = other.extraEvictClasses; 444 if (a == null) return false; 445 if (a.length != extraEvictClasses.length) return false; 446 for (int i = a.length - 1; i >= 0; i--) { 447 if (a[i] != extraEvictClasses[i]) return false; 448 } 449 return true; 450 } else { 451 return other.extraEvictClasses == null; 452 } 453 } 454 455 private boolean checkCandidate(QueryDetails other) { 456 if (candidateClass != null) { 457 if (candidateClass != other.candidateClass) { 458 return false; 459 } 460 } else { 461 if (other.candidateClass != null) { 462 return false; 463 } 464 } 465 return true; 466 } 467 468 public void parameterParsed(int index, String type, String name) { 469 if (VersantQuery.VERSANT_OPTIONS.equals(name) 470 || VersantQuery.JDO_GENIE_OPTIONS.equals(name)) { 471 if (optionsParamIndex >= 0) { 472 throw BindingSupportImpl.getInstance().runtime( 473 "The " + VersantQuery.VERSANT_OPTIONS + 474 " parameter may only appear once in the parameter declarations"); 475 } 476 optionsParamIndex = index; 477 } else { 478 if (paramTypes == null) { 479 paramTypes = new String [3]; 480 paramNames = new String [3]; 481 } else if (paramCount == paramTypes.length) { 482 int len = paramCount; 483 int n = len * 2; 484 String [] a = new String [n]; 485 System.arraycopy(paramTypes, 0, a, 0, len); 486 paramTypes = a; 487 a = new String [n]; 488 System.arraycopy(paramNames, 0, a, 0, len); 489 paramNames = a; 490 } 491 paramTypes[paramCount] = type; 492 paramNames[paramCount++] = name; 493 } 494 } 495 496 501 public int getParamCount() { 502 if (language == LANGUAGE_EJBQL) { 503 return -1; 504 } else { 505 return paramCount; 506 } 507 } 508 509 514 public int getTotalParamCount() { 515 if (language == LANGUAGE_EJBQL) { 516 return -1; 517 } else { 518 if (optionsParamIndex >= 0) return paramCount + 1; 519 return paramCount; 520 } 521 } 522 523 528 public String [] getParamTypes() { 529 return paramTypes; 530 } 531 532 537 public String [] getParamNames() { 538 return paramNames; 539 } 540 541 546 public String getParameters() { 547 int n = getParamCount(); 548 if (n == 0) return null; 549 CharBuf s = new CharBuf(); 550 for (int i = 0; i < n; i++) { 551 if (i > 0) s.append(','); 552 s.append(paramTypes[i]); 553 s.append(' '); 554 s.append(paramNames[i]); 555 } 556 return s.toString(); 557 } 558 559 public String getVariables() { 560 return variables; 561 } 562 563 public void setVariables(String variables) { 564 this.variables = checkString(variables); 565 } 566 567 public String getOrdering() { 568 return ordering; 569 } 570 571 public void setOrdering(String ordering) { 572 this.ordering = checkString(ordering); 573 } 574 575 public boolean isIgnoreCache() { 576 return ignoreCache; 577 } 578 579 583 public boolean isUseIgnoreCacheFromPM() { 584 return useIgnoreCacheFromPM; 585 } 586 587 public void setIgnoreCache(boolean ignoreCache) { 588 this.ignoreCache = ignoreCache; 589 } 590 591 public int getOptionsParamIndex() { 592 return optionsParamIndex; 593 } 594 595 public void setOptionsParamIndex(int optionsParamIndex) { 596 this.optionsParamIndex = optionsParamIndex; 597 } 598 599 public boolean hasJdoGenieOptions() { 600 return optionsParamIndex >= 0; 601 } 602 603 public int getFetchGroupIndex() { 604 return fetchGroupIndex; 605 } 606 607 public void setFetchGroupIndex(int fetchGroupIndex) { 608 this.fetchGroupIndex = fetchGroupIndex; 609 } 610 611 public boolean isRandomAccess() { 612 return randomAccess; 613 } 614 615 public void setRandomAccess(boolean randomAccess) { 616 this.randomAccess = randomAccess; 617 } 618 619 public boolean isCountOnSize() { 620 return countOnSize; 621 } 622 623 public void setCountOnSize(boolean countOnSize) { 624 this.countOnSize = countOnSize; 625 } 626 627 public int[] getExtraEvictClasses() { 628 return extraEvictClasses; 629 } 630 631 public void setExtraEvictClasses(int[] extraEvictClasses) { 632 this.extraEvictClasses = extraEvictClasses; 633 } 634 635 public void fillFrom(QueryDetails qd) { 636 language = qd.language; 638 candidateClass = qd.candidateClass; 639 col = qd.col; 640 subClasses = qd.subClasses; 641 filter = qd.filter; 642 result = qd.result; 643 grouping = qd.grouping; 644 ignoreCache = qd.ignoreCache; 645 unique = qd.unique; 646 imports = qd.imports; 647 variables = qd.variables; 648 ordering = qd.ordering; 649 paramCount = qd.paramCount; 650 paramTypes = qd.paramTypes; 651 paramNames = qd.paramNames; 652 optionsParamIndex = qd.optionsParamIndex; 653 fetchGroupIndex = qd.fetchGroupIndex; 654 randomAccess = qd.randomAccess; 655 countOnSize = qd.countOnSize; 656 maxResultCount = qd.maxResultCount; 657 resultBatchSize = qd.resultBatchSize; 658 extraEvictClasses = qd.extraEvictClasses; 659 cacheable = qd.cacheable; 660 bounded = qd.bounded; 661 } 662 663 664 665 668 public void clearExtentAndCol() { 669 this.col = null; 670 } 671 672 public void readExternal(ObjectInput s) throws IOException , 673 ClassNotFoundException { 674 language = s.read(); 675 candidateClass = (Class )s.readObject(); 676 filter = (String )s.readObject(); 677 result = (String )s.readObject(); 678 grouping = (String )s.readObject(); 679 unique = s.readInt(); 680 ignoreCache = s.readBoolean(); 681 useIgnoreCacheFromPM = s.readBoolean(); 682 imports = (String )s.readObject(); 683 variables = (String )s.readObject(); 684 ordering = (String )s.readObject(); 685 subClasses = s.readBoolean(); 686 687 paramCount = s.readShort(); 688 paramTypes = new String [paramCount]; 689 paramNames = new String [paramCount]; 690 for (int i = 0; i < paramCount; i++) { 691 paramTypes[i] = s.readUTF(); 692 paramNames[i] = s.readUTF(); 693 } 694 optionsParamIndex = s.readShort(); 695 696 fetchGroupIndex = s.readShort(); 697 randomAccess = s.readBoolean(); 698 countOnSize = s.readBoolean(); 699 maxResultCount = s.readInt(); 700 resultBatchSize = s.readInt(); 701 bounded = s.readBoolean(); 702 703 int n = s.readShort(); 704 if (n > 0) { 705 extraEvictClasses = new int[n]; 706 for (int i = 0; i < n; i++) extraEvictClasses[i] = s.readShort(); 707 } 708 709 cacheable = s.readByte(); 710 } 711 712 public void writeExternal(ObjectOutput s) throws IOException { 713 s.writeByte(language); 714 s.writeObject(candidateClass); 715 s.writeObject(filter); 716 s.writeObject(result); 717 s.writeObject(grouping); 718 s.writeInt(unique); 719 s.writeBoolean(ignoreCache); 720 s.writeBoolean(useIgnoreCacheFromPM); 721 s.writeObject(imports); 722 s.writeObject(variables); 723 s.writeObject(ordering); 724 s.writeBoolean(subClasses); 725 726 s.writeShort(paramCount); 727 for (int i = 0; i < paramCount; i++) { 728 s.writeUTF(paramTypes[i]); 729 s.writeUTF(paramNames[i]); 730 } 731 s.writeShort(optionsParamIndex); 732 733 s.writeShort(fetchGroupIndex); 734 s.writeBoolean(randomAccess); 735 s.writeBoolean(countOnSize); 736 s.writeInt(maxResultCount); 737 s.writeInt(resultBatchSize); 738 s.writeBoolean(bounded); 739 740 if (extraEvictClasses != null) { 741 int n = extraEvictClasses.length; 742 s.writeShort(n); 743 for (int i = 0; i < n; i++) s.writeShort(extraEvictClasses[i]); 744 } else { 745 s.writeShort(0); 746 } 747 748 s.writeByte(cacheable); 749 } 750 751 public void dump() { 752 StringBuffer sb = new StringBuffer (">>>>> QueryDetails: "); 753 sb.append("\n language = " + language); 754 sb.append("\n candidateClass = " + candidateClass); 755 sb.append("\n filter = " + filter); 756 sb.append("\n result = " + result); 757 sb.append("\n grouping = " + grouping); 758 sb.append("\n unique = " + unique); 759 sb.append("\n ignoreCache = " + ignoreCache); 760 sb.append("\n useIgnoreCacheFromPM = " + useIgnoreCacheFromPM); 761 sb.append("\n imports = " + imports); 762 sb.append("\n variables = " + variables); 763 sb.append("\n ordering = " + ordering); 764 sb.append("\n paramCount = " + paramCount); 765 for (int i = 0; i < paramCount; i++) { 766 sb.append("\n param["); 767 sb.append(i); 768 sb.append("] = '"); 769 sb.append(paramTypes[i]); 770 sb.append("' '"); 771 sb.append(paramNames[i]); 772 sb.append('\''); 773 } 774 sb.append("\n optionsParamIndex = " + optionsParamIndex); 775 sb.append("\n fetchGroupIndex = " + fetchGroupIndex); 776 sb.append("\n randomAccess = " + randomAccess); 777 sb.append("\n countOnSize = " + countOnSize); 778 sb.append("\n maxRows = " + maxResultCount); 779 sb.append("\n resultBatchSize = " + resultBatchSize); 780 sb.append("\n parallelCollectionFetch = " + bounded); 781 sb.append("\n cacheable = " + cacheable); 782 System.out.println(sb.toString()); 783 } 784 785 public void setCacheable(boolean on) { 786 cacheable = on ? TRUE : FALSE; 787 } 788 789 792 public int getCacheable() { 793 return cacheable; 794 } 795 796 } 797 | Popular Tags |