001// 002// Name 003// $RCSfile: KeyQuery.java,v $ 004// 005// Copyright 006// Copyright 2009-2015 Cloud Software Group, Inc. ALL RIGHTS RESERVED. 007// Cloud Software Group, Inc. Confidential Information 008// 009// History 010// $Revision: 1.1.2.38 $ $Date: 2015/01/27 03:25:07 $ 011// 012package com.kabira.platform; 013 014import java.util.ArrayList; 015import java.util.Iterator; 016import java.util.Map; 017import java.util.concurrent.ConcurrentHashMap; 018 019/** 020 * Class used to define a query and obtain results using keys. 021 * <p> 022 * Instances of this class are created by KeyManager, so it has no 023 * public constructors. 024 * <p> 025 * Once a query is defined, it may be executed multiple times. 026 */ 027public final class KeyQuery<T> 028{ 029 /** 030 * Returns the results of a query. 031 * 032 * @param objectLock LockMode to apply to each instance returned. 033 * 034 * @return Iterable containing set. 035 * 036 * @exception KeyIncompleteError 037 * All the fields for the key have not been defined. 038 * <p> 039 * Executes the previously defined query and returns the resulting set. 040 * For ordered keys, the default orderBy of ASCENDING is used. 041 */ 042 public Iterable<T> getResults( 043 LockMode objectLock) 044 throws KeyIncompleteError 045 { 046 validateExecution(); 047 if (objectLock == null) 048 { 049 throw new NullPointerException(); 050 } 051 if (m_hasKeyCoverage) 052 { 053 return new KeyResultSet<T>(this, objectLock); 054 } 055 assert( m_descriptor.m_ordered == true ); 056 return getResults(KeyOrderedBy.ASCENDING, objectLock); 057 } 058 059 /** 060 * Returns the results for a query using an ordered key. 061 * 062 * @param orderBy The order or the results. 063 * @param objectLock The lock applied to each instance. 064 * 065 * @return Iterable containing set. 066 * 067 * @exception KeyIncompleteError 068 * All the fields for the key have not been defined. 069 * 070 * @exception KeyIllegalKeyTypeError 071 * The key is not ordered. 072 * <p> 073 * Executes the previously defined query and returns the resulting set. 074 */ 075 public Iterable<T> getResults( 076 KeyOrderedBy orderBy, 077 LockMode objectLock) 078 throws KeyIncompleteError 079 { 080 validateExecution(); 081 validateOrdered(); 082 if (objectLock == null) 083 { 084 throw new NullPointerException(); 085 } 086 return new KeyResultSet<T>(this, orderBy, objectLock); 087 } 088 089 /** 090 * Returns the instance matching the given unique key. 091 * 092 * @param objectLock The object lock applied if an instance is found. 093 * 094 * @return Object containing result, or null if key not found. 095 * 096 * @exception KeyIncompleteError 097 * The fields for the key have not been defined. 098 * 099 * @exception KeyIllegalKeyTypeError 100 * The key is not unique. 101 * 102 * @exception KeyMalformedQueryError 103 * The query has range operators which may result multiple instances. 104 * <p> 105 * Executes the previously defined query and returns an instance. 106 */ 107 public T getSingleResult(LockMode objectLock) 108 throws KeyIncompleteError, KeyIllegalKeyTypeError, 109 KeyMalformedQueryError 110 { 111 validateExecution(); 112 if (m_descriptor.m_unique == false) 113 { 114 throw new KeyIllegalKeyTypeError("Key is not unique"); 115 } 116 if (m_descriptor.m_ordered == true && m_hasRangeOperators == true) 117 { 118 throw new KeyMalformedQueryError("Query has range operators"); 119 } 120 if (m_descriptor.m_ordered) 121 { 122 validateKeyCoverage(); 123 } 124 return attachObject(objectLock); 125 } 126 127 /** 128 * Returns the minimum value for the given ordered key. 129 * 130 * @param objectLock The object lock applied if an instance is found. 131 * 132 * @return Object containing result, or null if key not found. 133 * 134 * @exception KeyIllegalKeyTypeError 135 * The key is not ordered. 136 * 137 * @exception KeyMalformedQueryError 138 * An illegal operator was used when defining the query. 139 * <p> 140 * Executes the previously defined query (if any) and returns an 141 * instance containing the minimum value. If no query was defined, 142 * the instance containing the minimum key is returned. If a query was 143 * defined, the instance containing the minimum key value that 144 * matches the given fields is returned. 145 */ 146 public T getMinimumResult(LockMode objectLock) 147 throws KeyMalformedQueryError, KeyIllegalKeyTypeError 148 { 149 validateOrdered(); 150 if (m_query == null) 151 { 152 m_query = new CompiledQuery(); 153 m_query.m_keyInfo1 = new KeyInfo(); 154 } 155 CompiledQuery query = m_query; 156 if (m_query.m_filters != null) 157 { 158 query = compileOrderedQuery(CompileFilter.FILTER_NONE); 159 } 160 validateMinMaxQuery(query); 161 // 162 // If a range query, return the first element 163 // 164 if (m_query.m_keyInfo2 != null) 165 { 166 assert( query.m_hasRange == true ); 167 168 // 169 // The RangeQueryType_Minimum param is passed 170 // so the the iterator can distinguish between 171 // being call from getMiniumResult(), getMaxiumResult(), 172 // and getResults(), in order to call the correct 173 // store Query notifier method 174 // 175 Iterable<T> i = new KeyResultSet<T>( 176 this, KeyOrderedBy.ASCENDING, 177 objectLock, RangeQueryType_Minimum); 178 return i.iterator().next(); 179 } 180 181 return attachMinimum(query, objectLock); 182 } 183 184 /** 185 * Returns the maximum value for the given ordered key. 186 * 187 * @param objectLock The object lock applied if an instance is found. 188 * 189 * @return Object containing result, or null if key not found. 190 * 191 * @exception KeyIllegalKeyTypeError 192 * The key is not ordered. 193 * 194 * @exception KeyMalformedQueryError 195 * An illegal operator was used when defining the query. 196 * <p> 197 * Executes the previously defined query (if any) and returns an 198 * instance containing the maximum value. If no query was defined, 199 * the instance containing the maximum key is returned. If a query was 200 * defined, the instance containing the maximum key value that 201 * matches the given fields is returned. 202 */ 203 public T getMaximumResult(LockMode objectLock) 204 throws KeyMalformedQueryError, KeyIllegalKeyTypeError 205 { 206 validateOrdered(); 207 if (m_query == null) 208 { 209 m_query = new CompiledQuery(); 210 m_query.m_keyInfo1 = new KeyInfo(); 211 } 212 CompiledQuery query = m_query; 213 if (m_query.m_filters != null) 214 { 215 query = compileOrderedQuery(CompileFilter.FILTER_NONE); 216 } 217 validateMinMaxQuery(query); 218 // 219 // If a range query, return the last element 220 // 221 if (m_query.m_keyInfo2 != null) 222 { 223 assert( query.m_hasRange == true ); 224 // 225 // The RangeQueryType_Maximum param is passed 226 // so the the iterator can distinguish between 227 // being call from getMiniumResult(), getMaxiumResult(), 228 // and getResults(), in order to call the correct 229 // store Query notifier method 230 // 231 Iterable<T> i = new KeyResultSet<T>( 232 this, KeyOrderedBy.DESCENDING, 233 objectLock, RangeQueryType_Maximum); 234 return i.iterator().next(); 235 } 236 return attachMaximum(query, objectLock); 237 } 238 239 /** 240 * Returns the instance for the given unique key. 241 * 242 * @param objectLock The object lock applied if a pre-existing instance 243 * is found. 244 * @param additionalFields Additional field values to use if an 245 * instance in created. These values are ignored if 246 * the instance already exists. null can be specified 247 * if no additional field values are needed. 248 * 249 * @return Object containing result. 250 * 251 * @exception KeyIncompleteError 252 * The fields for the key have not been defined. 253 * 254 * @exception KeyIllegalKeyTypeError 255 * The key is not unique. 256 * 257 * @exception KeyIllegalFieldError 258 * A field in the additionalFields list is not valid. 259 * 260 * @exception KeyMalformedQueryError 261 * The query has range operators which may result multiple instances. 262 * <p> 263 * Executes the previously defined query and returns an instance. 264 * This method will atomically insure that an instance of 265 * the type will be created when searching for a instance by key. 266 * The additionalFields list passed in allows the programmer to 267 * populate secondary key fields if the instance is created. 268 * This should be used instead of doing: 269 *<pre> 270KeyedObject ko = kq.getSingleResult(lockMode); 271if (ko == null) 272{ 273 ko = new KeyedObject(keys); 274}</pre> 275 * <p> 276 * The above new can throw an ObjectNotUniqueError exception 277 * if another transaction creates the instance between the 278 * getSingleResult() and the new call. 279 */ 280 @SuppressWarnings("unchecked") 281 public T getOrCreateSingleResult( 282 LockMode objectLock, 283 KeyFieldValueList additionalFields) 284 throws KeyIncompleteError, KeyIllegalKeyTypeError, 285 KeyIllegalFieldError, KeyMalformedQueryError 286 { 287 validateExecution(); 288 if (m_descriptor.m_unique == false) 289 { 290 throw new KeyIllegalKeyTypeError( 291 "Key is not unique"); 292 } 293 if (m_descriptor.m_ordered == true && m_hasRangeOperators == true) 294 { 295 throw new KeyMalformedQueryError("Query has range operators"); 296 } 297 if (m_descriptor.m_ordered) 298 { 299 validateKeyCoverage(); 300 } 301 302 ArrayList<CreateBuffer> createValues = null; 303 304 if (additionalFields != null) 305 { 306 createValues = new ArrayList<CreateBuffer>(); 307 for (KeyFieldEntry fe : additionalFields.m_entries) 308 { 309 // 310 // We need to audit that these fields are 311 // not part of the key. Otherwise we'll 312 // create the wrong instance in the "on 313 // empty" case, since the key will 314 // subsequently be updated. 315 // 316 if (findField(fe)) 317 { 318 throw new KeyIllegalFieldError( 319 "Field " + fe.m_name + 320 " in additionalFields list " + 321 "is part of the key."); 322 } 323 CreateBuffer cb = new CreateBuffer(fe); 324 createValues.add(cb); 325 } 326 } 327 328 T obj = null; 329 boolean retry = true; 330 int retryCount = 0; 331 while (retry) 332 { 333 obj = attachObject(objectLock); 334 if (obj != null) 335 { 336 retry = false; 337 } 338 else 339 { 340 try 341 { 342 // 343 // Attempt to create the key'd object using the 344 // constructor. The placeholder created above will 345 // prevent another transaction from creating the 346 // instance from underneath us. 347 // 348 // Note: we cast and use the above SuppressWarnings 349 // annotation since KeyConstructor uses reflection so it 350 // cannot be a generic. 351 // 352 KeyConstructor kc = new KeyConstructor(); 353 for (KeyFieldEntry fe : m_entries) 354 { 355 kc.addKeyValue(fe.m_name, fe.m_value); 356 } 357 if (additionalFields != null) 358 { 359 for (KeyFieldEntry fe : additionalFields.m_entries) 360 { 361 kc.addKeyValue(fe.m_name, fe.m_value); 362 } 363 } 364 obj = (T)kc.invokeConstructor(m_descriptor.m_className); 365 if (obj == null) 366 { 367 // 368 // Cannot construct instance, create a shared 369 // memory image. 370 // 371 obj = createObject(createValues); 372 } 373 retry = false; 374 } 375 catch (ObjectNotUniqueError ex) 376 { 377 if (retryCount++ > MaxSelectRetries) 378 { 379 throw ex; 380 } 381 // 382 // Just ignore this exception, we'll try and select again. 383 // 384 } 385 } 386 } 387 return obj; 388 } 389 390 /** 391 * Returns the number of instances of the given key. 392 * 393 * @return Number of instances. 394 * 395 * @exception KeyIncompleteError 396 * All the fields for the key have not been defined. 397 * <p> 398 * Executes the previously defined query and returns the number of 399 * instances that would result. 400 * <p> 401 * No transaction locks are take when this method executes. 402 * This means the number returned by cardinality() may 403 * change even if called multiple times within a single 404 * transaction. 405 * 406 */ 407 public int cardinality() 408 throws KeyIncompleteError 409 { 410 validateExecution(); 411 412 KeyIterator<T> ki = new KeyIterator<T>(this, KeyOrderedBy.ASCENDING, 413 LockMode.NOLOCK, RangeQueryType_Range); 414 415 int cardinality = ki.size(); 416 ki.dispose(); 417 418 return cardinality; 419 } 420 421 /** 422 * Defines the fields that form a key query. 423 * 424 * @param keyFields The fields to use. 425 * 426 * @exception KeyIncompleteError 427 * All the fields for the key have not been defined. 428 * 429 * @exception KeyIllegalFieldError 430 * A given field is not part of the key. 431 * 432 * @exception KeyMalformedQueryError 433 * The resulting key lookup cannot perform a range query 434 * on an ordered key, or duplicate fields exist 435 * for a non-ordered key. 436 * <p> 437 * When executed, this defines the values used for a key lookup. 438 * Any previous query is overwritten. 439 */ 440 public void defineQuery( 441 KeyFieldValueList keyFields) 442 throws KeyIncompleteError, KeyIllegalFieldError, KeyMalformedQueryError 443 { 444 processFields(keyFields.getEntries()); 445 446 if (!m_descriptor.m_ordered) 447 { 448 validateKeyCoverage(); 449 } 450 else if (!m_hasKeyCoverage) 451 { 452 validateOrderedKey(); 453 } 454 455 m_query = compileQuery(); 456 } 457 458 /** 459 * Defines the fields that form a range query. 460 * 461 * @param keyFields The fields to use. 462 * 463 * @exception KeyIllegalFieldError 464 * A given field is not part of the key. 465 * 466 * @exception KeyMalformedQueryError 467 * The resulting key lookup cannot perform a range query 468 * on an ordered key, duplicate fields are defined 469 * for a non-ordered key, or a range query was attempted 470 * on a non-ordered key. 471 * <p> 472 * When executed, this defines the values used for a range query 473 * on an ordered key. Any previous query is overwritten. 474 */ 475 public void defineQuery( 476 KeyFieldValueRangeList keyFields) 477 throws KeyIllegalFieldError, KeyMalformedQueryError 478 { 479 validateOrdered(); 480 481 processFields(keyFields.getEntries()); 482 483 if (!m_hasKeyCoverage) 484 { 485 validateOrderedKey(); 486 } 487 488 m_query = compileQuery(); 489 } 490 491 /** 492 * Set the scope of query. 493 * <p> 494 * This method defines the scope of any subsequent queries that are 495 * executed. It can be called multiple times with different queryScope 496 * values. 497 * <p> 498 * @param queryScope Scope of Query. 499 * 500 * @exception IllegalArgumentException 501 * The queryScope failed audit due to a bad node list. 502 * @exception ResourceUnavailableException 503 * Access to distributed services failed. 504 * @see com.kabira.platform.QueryScope 505 */ 506 public final void setQueryScope( 507 final QueryScope queryScope) 508 throws IllegalArgumentException, ResourceUnavailableException 509 { 510 if (queryScope.getScope() == QueryScope.Scope.LOCAL) 511 { 512 m_queryScope = null; 513 } 514 else 515 { 516 ManagedObject.initializeDistributedQuery(); 517 queryScope.audit(); 518 m_queryScope = queryScope; 519 } 520 } 521 522 /** 523 * Creates a human readable query string. 524 * 525 * @exception KeyIncompleteError 526 * All the fields for the key have not been defined. 527 * <p> 528 * This method returns a string containing a "select" or "for" 529 * statement. The string also contains any optimization warnings for 530 * the defined query. 531 * This information can be used to help diagnose queries. 532 */ 533 public String toString() 534 throws KeyIncompleteError 535 { 536 String res = new String(); 537 538 if (m_descriptor.m_unique && m_hasKeyCoverage) 539 { 540 res += "select obj from "; 541 } 542 else 543 { 544 res += "for obj in "; 545 } 546 res += m_descriptor.m_className; 547 res += " using "; 548 res += m_descriptor.m_keyName; 549 res += " where ("; 550 551 boolean firstField = true; 552 for (KeyFieldEntry fe : m_entries) 553 { 554 if (!firstField) 555 { 556 res += " && "; 557 } 558 else 559 { 560 firstField = false; 561 } 562 res += fe.m_name; 563 res += getComparisonOp(fe.m_op); 564 res += fe.m_value; 565 } 566 res += ")"; 567 if (m_descriptor.m_unique && m_hasKeyCoverage) 568 { 569 res += ";"; 570 } 571 else 572 { 573 res += " { }"; 574 } 575 576 if (m_descriptor.m_unique && m_hasKeyCoverage) 577 { 578 KeyConstructor kc = new KeyConstructor(); 579 for (KeyFieldEntry fe : m_entries) 580 { 581 kc.addKeyValue(fe.m_name, fe.m_value); 582 } 583 res += " Java constructor: "; 584 res += kc.displayConstructor(m_descriptor.m_className); 585 } 586 587 if (m_query != null && m_query.m_filters != null) 588 { 589 for (int i = 0; i < m_query.m_filters.size(); i++) 590 { 591 KeyInfo filter = m_query.m_filters.get(i); 592 int keyDepth = 0; 593 594 for (FieldDescriptor fd : m_descriptor.m_fields) 595 { 596 if (keyDepth == filter.m_keyDepth) 597 { 598 res += " [ Warning: field '"; 599 res += fd.m_name; 600 res += "' filtered ]"; 601 break; 602 } 603 keyDepth++; 604 } 605 } 606 } 607 608 return res; 609 } 610 611 /** 612 * Resets internal caches. 613 * <p> 614 * Used internally when replacing type descriptors. Applications 615 * should not call this. 616 */ 617 public static void resetCache() 618 { 619 m_map = new ConcurrentHashMap<String, KeyDescriptor>(); 620 } 621 622 ///////////////////////////////////////////////////////////////// 623 // 624 // Private fields, classes and utility routines 625 // 626 ///////////////////////////////////////////////////////////////// 627 628 // 629 // Note: The following enumeration "know" about the actual values 630 // in the C++ enum definitions. We use them instead of java enums 631 // to avoid having to map things in JNI code. 632 // 633 634 // enumeration values for SWRBTree::RBDirection 635 private static final int SWRBTreeAscending = 1; 636 private static final int SWRBTreeDescending = 2; 637 638 // enumeration values for OSKeyOpt::ObjectLock 639 static final int KeyOptReadLock = 1; 640 static final int KeyOptWriteLock = 2; 641 static final int KeyOptNoLock = 3; 642 643 // enumeration values for CGObject::MaxSelectRetries 644 private static final int MaxSelectRetries = 10; 645 646 // enumeration values for ObjSrv::RangeOperator 647 static final int ObjSrv_EQ = 1; 648 static final int ObjSrv_NEQ = 2; 649 static final int ObjSrv_GTE = 3; 650 static final int ObjSrv_GT = 4; 651 static final int ObjSrv_LTE = 5; 652 static final int ObjSrv_LT = 6; 653 654 // enumeration values for CGKeyIterator::RangeQueryType 655 private static final int RangeQueryType_Range = 1; 656 private static final int RangeQueryType_Minimum = 2; 657 private static final int RangeQueryType_Maximum = 3; 658 659 // enumeration values for DSETypeCode 660 private static final int tkInvalid = 0; 661 private static final int tkShort = 1; 662 private static final int tkLong = 2; 663 private static final int tkLongLong = 3; 664 private static final int tkUShort = 4; 665 private static final int tkULong = 5; 666 private static final int tkULongLong = 6; 667 private static final int tkFloat = 7; 668 private static final int tkDouble = 8; 669 private static final int tkBoolean = 9; 670 private static final int tkChar = 10; 671 private static final int tkOctet = 11; 672 private static final int tkObjectReference = 12; 673 private static final int tkStruct = 13; 674 private static final int tkEnum = 14; 675 private static final int tkString = 15; 676 private static final int tkSequence = 16; 677 private static final int tkArray = 17; 678 private static final int tkException = 18; 679 private static final int tkVoid = 19; 680 private static final int tkOffset = 20; 681 private static final int tkSize = 21; 682 private static final int tkWChar = 22; 683 private static final int tkAny = 23; 684 private static final int tkNative = 24; 685 private static final int tkType = 25; 686 private static final int tkUnion = 26; 687 private static final int tkDate = 27; 688 private static final int tkBinary = 28; 689 690 enum CompileFilter 691 { 692 FILTER_LTEGTE, 693 FILTER_NONE 694 } 695 696 // 697 // Return a string containing the Java type for the given typeCode 698 // 699 private static String getTCString(int tc) 700 { 701 String ret = "<unknown>"; 702 switch (tc) 703 { 704 case tkShort: 705 case tkUShort: 706 ret = "short"; 707 break; 708 case tkLong: 709 case tkULong: 710 ret = "int"; 711 break; 712 case tkULongLong: 713 case tkLongLong: 714 ret = "long"; 715 break; 716 case tkFloat: 717 ret = "float"; 718 break; 719 case tkDouble: 720 ret = "double"; 721 break; 722 case tkBoolean: 723 ret = "boolean"; 724 break; 725 case tkWChar: 726 ret = "char"; 727 break; 728 case tkChar: 729 case tkOctet: 730 ret = "byte"; 731 break; 732 case tkSequence: 733 ret = "Array"; 734 break; 735 case tkObjectReference: 736 ret = "Object"; 737 break; 738 case tkString: 739 ret = "String"; 740 break; 741 case tkDate: 742 ret = "java.util.Date"; 743 break; 744 default: 745 break; 746 } 747 return ret; 748 } 749 750 // 751 // Return a string containing the operation 752 // 753 private static String getComparisonOp(KeyComparisonOperator op) 754 { 755 String ret = null; 756 switch (op) 757 { 758 case EQ: 759 ret = " == "; 760 break; 761 case NEQ: 762 ret = " != "; 763 break; 764 case GTE: 765 ret = " >= "; 766 break; 767 case GT: 768 ret = " > "; 769 break; 770 case LTE: 771 ret = " <= "; 772 break; 773 case LT: 774 ret = " < "; 775 break; 776 } 777 return ret; 778 } 779 780 // 781 // Return the KTP typeCode for the given java object 782 // 783 private static int getTypeCode(Object obj) 784 { 785 int typeCode = tkInvalid; 786 if (obj instanceof Integer) 787 { 788 typeCode = tkLong; 789 } 790 else if (obj instanceof Long) 791 { 792 typeCode = tkLongLong; 793 } 794 else if (obj instanceof String) 795 { 796 typeCode = tkString; 797 } 798 else if (obj instanceof Short) 799 { 800 typeCode = tkShort; 801 } 802 else if (obj instanceof Character) 803 { 804 typeCode = tkWChar; 805 } 806 else if (obj instanceof Float) 807 { 808 typeCode = tkFloat; 809 } 810 else if (obj instanceof Double) 811 { 812 typeCode = tkDouble; 813 } 814 else if (obj instanceof Enum) 815 { 816 typeCode = tkEnum; 817 } 818 else if (obj instanceof java.util.Date) 819 { 820 typeCode = tkDate; 821 } 822 else if (obj instanceof Boolean) 823 { 824 typeCode = tkBoolean; 825 } 826 else if (obj instanceof Byte) 827 { 828 typeCode = tkOctet; 829 } 830 else 831 { 832 Class<?> cls = obj.getClass(); 833 if (cls.isArray()) 834 { 835 typeCode = tkSequence; 836 } 837 else 838 { 839 typeCode = tkObjectReference; 840 } 841 } 842 assert( typeCode != tkInvalid ); 843 return typeCode; 844 } 845 846 // 847 // Return the number of bytes a null key slot would contain for 848 // the given typeCode. Used when building key filters. 849 // 850 private static int getKeyOffset(int tc) 851 { 852 int size = 0; 853 switch (tc) 854 { 855 case tkShort: 856 case tkUShort: 857 size = 2; 858 break; 859 case tkLong: 860 case tkULong: 861 case tkFloat: 862 case tkWChar: 863 case tkEnum: 864 size = 4; 865 break; 866 case tkULongLong: 867 case tkLongLong: 868 case tkDouble: 869 case tkDate: 870 size = 8; 871 break; 872 case tkBoolean: 873 case tkChar: 874 case tkOctet: 875 size = 1; 876 break; 877 case tkObjectReference: 878 size = 24; 879 break; 880 case tkString: 881 size = 8; // zero length string 882 break; 883 } 884 assert( size != 0 ); 885 return size; 886 } 887 888 private DistributedQuery getDistributedQuery() 889 { 890 return ManagedObject.getDistributedQuery(); 891 } 892 893 // 894 // Descriptors used to manage key information 895 // 896 private static class FieldDescriptor 897 { 898 FieldDescriptor(String name, int typeCode) 899 { 900 m_name = name; 901 m_typeCode = typeCode; 902 } 903 private final String m_name; 904 private final int m_typeCode; 905 906 // 907 // Return runtime mapping as per the ERD. 908 // 909 int getTypeCode() 910 { 911 int typeCode = m_typeCode; 912 switch (typeCode) 913 { 914 case tkChar: 915 typeCode = tkOctet; 916 break; 917 case tkUShort: 918 typeCode = tkShort; 919 break; 920 case tkULong: 921 typeCode = tkLong; 922 break; 923 case tkULongLong: 924 typeCode = tkLongLong; 925 break; 926 default: 927 break; 928 } 929 assert( typeCode != tkInvalid ); 930 return typeCode; 931 } 932 } 933 934 private static Map<String, KeyDescriptor> m_map = 935 new ConcurrentHashMap<String, KeyDescriptor>(); 936 937 private static class KeyDescriptor 938 { 939 KeyDescriptor(String className, String keyName) 940 { 941 m_className = className; 942 m_keyName = keyName; 943 m_fields = new ArrayList<FieldDescriptor>(); 944 m_ordered = false; 945 m_unique = false; 946 } 947 // 948 // These are define by the KeyQuery() constructor 949 // 950 private final String m_className; 951 private final String m_keyName; 952 // 953 // These are all populated by _getKeyDescriptor() 954 // 955 private ArrayList<FieldDescriptor> m_fields; 956 private boolean m_ordered; 957 private boolean m_unique; 958 private int m_objDomainId; 959 private int m_objTypeId; 960 private int m_keyDomainId; 961 private int m_keyTypeId; 962 } 963 964 // 965 // Class used to support additional fields in queries. 966 // 967 private static class CreateBuffer extends KeyBuffer 968 { 969 CreateBuffer(KeyFieldEntry fe) throws KeyIllegalFieldError 970 { 971 m_name = fe.m_name; 972 m_typeCode = getTypeCode(fe.m_value); 973 try 974 { 975 writeObject(fe.m_value); 976 } 977 catch (IllegalArgumentException iae) 978 { 979 throw new KeyIllegalFieldError( 980 "Field " + fe.m_name + " containing " + 981 fe.m_value.getClass() + " is not supported"); 982 } 983 } 984 String m_name; 985 int m_typeCode; 986 } 987 988 // 989 // Class containing a compiled query 990 // 991 private static class CompiledQuery 992 { 993 CompiledQuery() 994 { 995 m_keyInfo1 = null; 996 m_keyInfo2 = null; 997 m_filters = null; 998 m_hasRange = false; 999 } 1000 1001 void addRange(KeyInfo keyInfo) 1002 { 1003 if (m_keyInfo1 == null) 1004 { 1005 m_keyInfo1 = keyInfo; 1006 } 1007 else 1008 { 1009 assert( m_keyInfo2 == null ); 1010 m_keyInfo2 = keyInfo; 1011 } 1012 m_hasRange = true; 1013 } 1014 1015 void addKeyInfo(KeyInfo keyInfo) 1016 { 1017 assert( !m_hasRange ); 1018 assert( m_keyInfo1 == null ); 1019 m_keyInfo1 = keyInfo; 1020 } 1021 1022 void addFilter(KeyInfo keyInfo) 1023 { 1024 assert( m_hasRange ); 1025 if (m_filters == null) 1026 { 1027 m_filters = new ArrayList<KeyInfo>(); 1028 } 1029 m_filters.add(keyInfo); 1030 } 1031 1032 KeyInfo m_keyInfo1; 1033 KeyInfo m_keyInfo2; 1034 ArrayList<KeyInfo> m_filters; 1035 boolean m_hasRange; 1036 } 1037 1038 // 1039 // Private data members that use the above private classes 1040 // 1041 private KeyDescriptor m_descriptor; 1042 private CompiledQuery m_query; 1043 private ArrayList<KeyFieldEntry> m_entries; 1044 private boolean m_hasKeyCoverage; 1045 private boolean m_hasRangeOperators; 1046 private QueryScope m_queryScope; 1047 1048 // 1049 // Class that implements the Iterable returned from getResults() 1050 // 1051 private class KeyResultSet<T extends Object> 1052 implements Iterable<T> 1053 { 1054 KeyOrderedBy m_orderBy; 1055 LockMode m_objectLock; 1056 int m_rangeQueryType; 1057 final KeyQuery<T> m_keyQuery; 1058 1059 KeyResultSet( 1060 KeyQuery<T> keyQuery, 1061 KeyOrderedBy orderBy, 1062 LockMode objectLock) 1063 { 1064 m_keyQuery = keyQuery; 1065 m_orderBy = orderBy; 1066 m_objectLock = objectLock; 1067 m_rangeQueryType = RangeQueryType_Range; 1068 } 1069 KeyResultSet( 1070 KeyQuery<T> keyQuery, 1071 KeyOrderedBy orderBy, 1072 LockMode objectLock, 1073 int rangeQueryType) 1074 { 1075 m_keyQuery = keyQuery; 1076 m_orderBy = orderBy; 1077 m_objectLock = objectLock; 1078 m_rangeQueryType = rangeQueryType; 1079 } 1080 KeyResultSet(KeyQuery<T> keyQuery, LockMode objectLock) 1081 { 1082 m_keyQuery = keyQuery; 1083 m_orderBy = KeyOrderedBy.ASCENDING; 1084 m_objectLock = objectLock; 1085 m_rangeQueryType = RangeQueryType_Range; 1086 } 1087 1088 @Override 1089 public Iterator<T> iterator() 1090 { 1091 return new KeyIterator<T>( 1092 m_keyQuery, m_orderBy, m_objectLock, m_rangeQueryType); 1093 } 1094 } 1095 1096 // 1097 // Class that implements the Iterator returned from Iterable 1098 // 1099 private static class KeyIterator<T extends Object> 1100 implements java.util.Iterator<T> 1101 { 1102 private long m_cHandle; 1103 private T m_next; 1104 1105 KeyIterator( 1106 KeyQuery<T> keyQuery, 1107 KeyOrderedBy orderBy, 1108 LockMode objectLock, 1109 int rangeQueryType) 1110 { 1111 final CompiledQuery compiledQuery = keyQuery.m_query; 1112 final KeyDescriptor keyDescriptor = keyQuery.m_descriptor; 1113 final QueryScope queryScope = keyQuery.m_queryScope; 1114 DistributedQuery distributedQuery = null; 1115 1116 if (queryScope != null) 1117 { 1118 distributedQuery = keyQuery.getDistributedQuery(); 1119 } 1120 1121 assert( compiledQuery.m_keyInfo1 != null ); 1122 if (compiledQuery.m_hasRange == false) 1123 { 1124 if (queryScope != null && distributedQuery != null) 1125 { 1126 distributedQuery.loadObjects( 1127 queryScope, 1128 keyDescriptor.m_objDomainId, 1129 keyDescriptor.m_objTypeId, 1130 keyDescriptor.m_keyDomainId, 1131 keyDescriptor.m_keyTypeId, 1132 compiledQuery.m_keyInfo1.array(), 1133 mapObjectLock(objectLock)); 1134 } 1135 m_cHandle = _initKey( 1136 keyDescriptor.m_objDomainId, 1137 keyDescriptor.m_objTypeId, 1138 keyDescriptor.m_keyDomainId, 1139 keyDescriptor.m_keyTypeId, 1140 mapObjectLock(objectLock), 1141 compiledQuery.m_keyInfo1.array()); 1142 } 1143 else if (compiledQuery.m_keyInfo2 == null) 1144 { 1145 assert( compiledQuery.m_hasRange == true ); 1146 assert( compiledQuery.m_keyInfo2 == null ); 1147 KeyInfo [] filters = (compiledQuery.m_filters == null) 1148 ? null : compiledQuery.m_filters.toArray(new KeyInfo[0]); 1149 if (queryScope != null && distributedQuery != null) 1150 { 1151 distributedQuery.loadRange1( 1152 queryScope, 1153 keyDescriptor.m_objDomainId, 1154 keyDescriptor.m_objTypeId, 1155 keyDescriptor.m_keyDomainId, 1156 keyDescriptor.m_keyTypeId, 1157 keyQuery.mapOrderBy(orderBy), 1158 mapObjectLock(objectLock), 1159 compiledQuery.m_keyInfo1.m_keyDepth, 1160 compiledQuery.m_keyInfo1.m_rop, 1161 compiledQuery.m_keyInfo1.array(), 1162 filters); 1163 } 1164 m_cHandle = _initRange1( 1165 keyDescriptor.m_objDomainId, 1166 keyDescriptor.m_objTypeId, 1167 keyDescriptor.m_keyDomainId, 1168 keyDescriptor.m_keyTypeId, 1169 keyQuery.mapOrderBy(orderBy), 1170 mapObjectLock(objectLock), 1171 compiledQuery.m_keyInfo1.m_keyDepth, 1172 compiledQuery.m_keyInfo1.m_rop, 1173 compiledQuery.m_keyInfo1.array(), 1174 filters); 1175 } 1176 else 1177 { 1178 assert( compiledQuery.m_hasRange == true ); 1179 assert( compiledQuery.m_keyInfo2 != null ); 1180 KeyInfo [] filters = (compiledQuery.m_filters == null) 1181 ? null : compiledQuery.m_filters.toArray(new KeyInfo[0]); 1182 if (queryScope != null && distributedQuery != null) 1183 { 1184 distributedQuery.loadRange2( 1185 queryScope, 1186 keyDescriptor.m_objDomainId, 1187 keyDescriptor.m_objTypeId, 1188 keyDescriptor.m_keyDomainId, 1189 keyDescriptor.m_keyTypeId, 1190 keyQuery.mapOrderBy(orderBy), 1191 mapObjectLock(objectLock), 1192 compiledQuery.m_keyInfo1.m_keyDepth, 1193 compiledQuery.m_keyInfo1.m_rop, 1194 compiledQuery.m_keyInfo1.array(), 1195 compiledQuery.m_keyInfo2.m_keyDepth, 1196 compiledQuery.m_keyInfo2.m_rop, 1197 compiledQuery.m_keyInfo2.array(), 1198 filters, 1199 rangeQueryType); 1200 } 1201 m_cHandle = _initRange2( 1202 keyDescriptor.m_objDomainId, 1203 keyDescriptor.m_objTypeId, 1204 keyDescriptor.m_keyDomainId, 1205 keyDescriptor.m_keyTypeId, 1206 keyQuery.mapOrderBy(orderBy), 1207 mapObjectLock(objectLock), 1208 compiledQuery.m_keyInfo1.m_keyDepth, 1209 compiledQuery.m_keyInfo1.m_rop, 1210 compiledQuery.m_keyInfo1.array(), 1211 compiledQuery.m_keyInfo2.m_keyDepth, 1212 compiledQuery.m_keyInfo2.m_rop, 1213 compiledQuery.m_keyInfo2.array(), 1214 filters, 1215 rangeQueryType); 1216 } 1217 m_next = _next(m_cHandle); 1218 } 1219 1220 public boolean hasNext() 1221 { 1222 return (m_next != null); 1223 } 1224 1225 public T next() 1226 { 1227 1228 T t = m_next; 1229 1230 if (m_cHandle != 0) 1231 { 1232 m_next = _next(m_cHandle); 1233 1234 if (t == null) 1235 { 1236 dispose(); 1237 } 1238 } 1239 1240 return t; 1241 } 1242 1243 public void remove() 1244 { 1245 throw new UnsupportedOperationException(); 1246 } 1247 1248 private void dispose() 1249 { 1250 if (m_cHandle != 0) 1251 { 1252 _delete(m_cHandle); 1253 } 1254 m_cHandle = 0; 1255 m_next = null; 1256 } 1257 1258 protected void finalize() 1259 { 1260 dispose(); 1261 } 1262 1263 int size() 1264 { 1265 return _size(m_cHandle); 1266 } 1267 1268 native long _initKey( 1269 int objDomainId, 1270 int objTypeId, 1271 int keyDomainId, 1272 int keyTypeId, 1273 int objLock, 1274 byte [] keyData); 1275 native long _initRange1( 1276 int objDomainId, 1277 int objTypeId, 1278 int keyDomainId, 1279 int keyTypeId, 1280 int direction, 1281 int objLock, 1282 int keyDepth, 1283 int rop, 1284 byte [] keyData, 1285 KeyInfo [] filters); 1286 native long _initRange2( 1287 int objDomainId, 1288 int objTypeId, 1289 int keyDomainId, 1290 int keyTypeId, 1291 int direction, 1292 int objLock, 1293 int keyDepth1, 1294 int rop1, 1295 byte [] keyData1, 1296 int keyDepth2, 1297 int rop2, 1298 byte [] keyData2, 1299 KeyInfo [] filters, 1300 int queryType); 1301 1302 native int _size(long cHandle); 1303 native T _next(long cHandle); 1304 native void _delete(long cHandle); 1305 } 1306 1307 // 1308 // Constructors are not exposed. 1309 // 1310 private KeyQuery() { } 1311 KeyQuery( 1312 final java.lang.Class<T> klass, 1313 final String keyName) throws KeyUnknownKeyNameError 1314 { 1315 init(klass.getName(), keyName); 1316 } 1317 KeyQuery( 1318 final String className, 1319 final String keyName) throws KeyUnknownKeyNameError 1320 { 1321 init(className, keyName); 1322 } 1323 1324 void init( 1325 final String className, 1326 final String keyName) throws KeyUnknownKeyNameError 1327 { 1328 String keyDescriptorKey = className + "." + keyName; 1329 1330 m_descriptor = m_map.get(keyDescriptorKey); 1331 1332 if (m_descriptor == null) 1333 { 1334 m_descriptor = new KeyDescriptor(className, keyName); 1335 1336 if (!_getKeyDescriptor(m_descriptor)) 1337 { 1338 throw new KeyUnknownKeyNameError( 1339 "Unknown keyName " + keyName); 1340 } 1341 1342 // No synchronization is needed here. If two threads 1343 // get here at the same time, the second put will replace 1344 // the first, and the GC will clean up at some later time. 1345 m_map.put(keyDescriptorKey, m_descriptor); 1346 } 1347 m_hasKeyCoverage = false; 1348 m_hasRangeOperators = false; 1349 m_queryScope = null; 1350 } 1351 1352 private void processFields(ArrayList<KeyFieldEntry> entries) 1353 throws KeyIllegalFieldError, KeyMalformedQueryError 1354 { 1355 // 1356 // Clear out previous query to insure validateExecution() 1357 // fails if the new query encounters an error. 1358 // 1359 m_query = null; 1360 1361 // 1362 // entries contains a copy of the KeyFieldEntry array defined by 1363 // the user. We keep a copy around mostly for so that 1364 // toString() can access it, otherwise we could just pass 1365 // it around for processing and compilation. 1366 // 1367 m_entries = entries; 1368 1369 // 1370 // Validate the fields we just stored. 1371 // 1372 validateFields(); 1373 1374 // 1375 // Determine if the fields cover the key. 1376 // 1377 checkForKeyCoverage(); 1378 } 1379 1380 private void validateFields() 1381 throws KeyIllegalFieldError, KeyMalformedQueryError 1382 { 1383 // 1384 // Validate each field 1385 // 1386 int count = 0; 1387 for (KeyFieldEntry fe : m_entries) 1388 { 1389 validateField(fe); 1390 count += 1; 1391 } 1392 if (count == 0) 1393 { 1394 throw new KeyMalformedQueryError("No fields defined"); 1395 } 1396 1397 // 1398 // Check for dups 1399 // 1400 if ((!m_descriptor.m_ordered) && (count > 1)) 1401 { 1402 validateNoDups(); 1403 } 1404 } 1405 1406 private void validateField(KeyFieldEntry fe) 1407 throws KeyIllegalFieldError, KeyMalformedQueryError 1408 { 1409 boolean found = false; 1410 1411 for (FieldDescriptor fd : m_descriptor.m_fields) 1412 { 1413 if (fe.m_name.equals(fd.m_name)) 1414 { 1415 validateValue(fd, fe.m_value); 1416 found = true; 1417 } 1418 } 1419 if (!found) 1420 { 1421 throw new KeyIllegalFieldError( 1422 "Field " + fe.m_name + 1423 " is not part of the key"); 1424 } 1425 } 1426 1427 private boolean findField(KeyFieldEntry fe) 1428 { 1429 boolean found = false; 1430 1431 for (FieldDescriptor fd : m_descriptor.m_fields) 1432 { 1433 if (fe.m_name.equals(fd.m_name)) 1434 { 1435 return true; 1436 } 1437 } 1438 return false; 1439 } 1440 1441 private void validateNoDups() 1442 throws KeyMalformedQueryError 1443 { 1444 assert( !m_descriptor.m_ordered ); 1445 1446 for (FieldDescriptor fd : m_descriptor.m_fields) 1447 { 1448 int count = 0; 1449 for (KeyFieldEntry fe : m_entries) 1450 { 1451 if (fd.m_name.equals(fe.m_name)) 1452 { 1453 count += 1; 1454 } 1455 } 1456 if (count > 1) 1457 { 1458 throw new KeyMalformedQueryError( 1459 "Field " + fd.m_name + 1460 " exists more than once in " + 1461 "the KeyFieldValueList list"); 1462 } 1463 } 1464 } 1465 1466 private void validateValue(FieldDescriptor fd, Object value) 1467 throws KeyIllegalFieldError 1468 { 1469 assert( value != null ); 1470 1471 int typeCode = getTypeCode(value); 1472 1473 if (typeCode != fd.getTypeCode()) 1474 { 1475 throw new KeyIllegalFieldError( 1476 "Illegal type " + getTCString(typeCode) + 1477 " for field " + fd.m_name + ", expected " + 1478 getTCString(fd.getTypeCode())); 1479 } 1480 } 1481 1482 private void checkForKeyCoverage() 1483 { 1484 // 1485 // If any of the field entries are not ==, we don't have 1486 // key coverage. 1487 // 1488 for (KeyFieldEntry fe : m_entries) 1489 { 1490 if (fe.m_op != KeyComparisonOperator.EQ) 1491 { 1492 m_hasKeyCoverage = false; 1493 m_hasRangeOperators = true; 1494 return; 1495 } 1496 } 1497 1498 // 1499 // If all fields are defined once and only one we have 1500 // a complete key. 1501 // 1502 int count = 0; 1503 int [] fieldCnt = new int[m_descriptor.m_fields.size()]; 1504 for (FieldDescriptor fd : m_descriptor.m_fields) 1505 { 1506 fieldCnt[count] = 0; 1507 for (KeyFieldEntry fe : m_entries) 1508 { 1509 if (fd.m_name.equals(fe.m_name)) 1510 { 1511 fieldCnt[count] += 1; 1512 } 1513 } 1514 count += 1; 1515 } 1516 m_hasKeyCoverage = true; 1517 for (int i = 0; i < count; i++) 1518 { 1519 if (fieldCnt[i] != 1) 1520 { 1521 m_hasKeyCoverage = false; 1522 break; 1523 } 1524 } 1525 } 1526 1527 // 1528 // If key coverage doesn't exist, make sure ordered query 1529 // isn't malformed. 1530 // 1531 private void validateKeyCoverage() 1532 throws KeyIncompleteError 1533 { 1534 if (!m_hasKeyCoverage) 1535 { 1536 // 1537 // Build missing list. Note that we ignore dups, since 1538 // KeyMalformedQueryError is thrown when this happens. 1539 // 1540 String missing = ""; 1541 for (FieldDescriptor fd : m_descriptor.m_fields) 1542 { 1543 boolean found = false; 1544 for (KeyFieldEntry fe : m_entries) 1545 { 1546 if (fd.m_name.equals(fe.m_name)) 1547 { 1548 found = true; 1549 break; 1550 } 1551 } 1552 if (found == false) 1553 { 1554 missing += ", missing field '" + fd.m_name + "'"; 1555 } 1556 } 1557 throw new KeyIncompleteError( 1558 "Not all required fields are present" + missing); 1559 } 1560 } 1561 1562 // 1563 // If key coverage doesn't exist, make sure ordered query 1564 // isn't malformed. 1565 // 1566 private void validateOrderedKey() 1567 throws KeyMalformedQueryError 1568 { 1569 assert( !m_hasKeyCoverage ); 1570 1571 String firstField; 1572 int numKeys = 0; 1573 1574 firstField = m_descriptor.m_fields.get(0).m_name; 1575 1576 for (KeyFieldEntry fe : m_entries) 1577 { 1578 if (!fe.m_name.equals(firstField) && numKeys == 0) 1579 { 1580 throw new KeyMalformedQueryError( 1581 "Range queries must use the '" + 1582 firstField + 1583 "' field as the first entry"); 1584 } 1585 if (fe.m_op == KeyComparisonOperator.NEQ && 1586 numKeys == 0) 1587 { 1588 throw new KeyMalformedQueryError( 1589 "Illegal operator != in range query"); 1590 } 1591 numKeys += 1; 1592 } 1593 } 1594 1595 private void validateMinMaxQuery(CompiledQuery query) 1596 throws KeyMalformedQueryError 1597 { 1598 if (m_entries != null) 1599 { 1600 for (KeyFieldEntry fe : m_entries) 1601 { 1602 if (fe.m_op != KeyComparisonOperator.EQ && 1603 fe.m_op != KeyComparisonOperator.GTE && 1604 fe.m_op != KeyComparisonOperator.LTE) 1605 { 1606 throw new KeyMalformedQueryError( 1607 "Illegal operator" + getComparisonOp(fe.m_op) + 1608 "used in query \"" + this + "\""); 1609 } 1610 } 1611 } 1612 if (query.m_filters != null) 1613 { 1614 throw new KeyMalformedQueryError( 1615 "filter present on query \"" + this + "\""); 1616 } 1617 } 1618 1619 private void validateExecution() 1620 throws KeyIncompleteError 1621 { 1622 if (m_query == null) 1623 { 1624 throw new KeyIncompleteError("No query has been defined"); 1625 } 1626 if (m_entries == null) 1627 { 1628 throw new KeyIncompleteError("No fields have been defined"); 1629 } 1630 1631 // We should have passed all audits here 1632 assert( m_hasKeyCoverage || m_descriptor.m_ordered ); 1633 } 1634 1635 private void validateOrdered() 1636 throws KeyIllegalKeyTypeError 1637 { 1638 if (m_descriptor.m_ordered == false) 1639 { 1640 throw new KeyIllegalKeyTypeError( 1641 "Key is not ordered"); 1642 } 1643 } 1644 1645 private CompiledQuery compileSimpleQuery() 1646 { 1647 assert( m_hasKeyCoverage == true ); 1648 1649 CompiledQuery query = new CompiledQuery(); 1650 1651 KeyInfo keyInfo = new KeyInfo(); 1652 1653 // 1654 // build key data based on field order 1655 // 1656 for (FieldDescriptor fd : m_descriptor.m_fields) 1657 { 1658 for (KeyFieldEntry fe : m_entries) 1659 { 1660 if (fd.m_name.equals(fe.m_name)) 1661 { 1662 keyInfo.addKeyData(fe.m_value); 1663 break; 1664 } 1665 } 1666 } 1667 1668 query.addKeyInfo(keyInfo); 1669 1670 return query; 1671 } 1672 1673 private CompiledQuery compileOrderedQuery(CompileFilter filter) 1674 { 1675 assert( m_descriptor.m_ordered == true ); 1676 1677 CompiledQuery query = new CompiledQuery(); 1678 1679 // 1680 // Build first range. This is either a multi-part key 1681 // defined using == clauses, or a one field key using 1682 // another comparison operator. 1683 // 1684 String firstField = m_descriptor.m_fields.get(0).m_name; 1685 Iterator<KeyFieldEntry> iter = m_entries.iterator(); 1686 1687 assert( iter.hasNext() ); 1688 KeyFieldEntry fe = iter.next(); 1689 1690 assert( firstField.equals(fe.m_name) ); 1691 assert( fe.m_op != KeyComparisonOperator.NEQ ); 1692 KeyComparisonOperator firstOp = fe.m_op; 1693 1694 KeyInfo keyInfo = new KeyInfo(mapComparisonOp(fe.m_op)); 1695 1696 if (fe.m_op == KeyComparisonOperator.EQ) 1697 { 1698 // 1699 // Build the key based on the number of == operators. 1700 // 1701 createEqualsKey(keyInfo, filter); 1702 1703 // 1704 // Move the iterator to the next field based on 1705 // the key depth of the built key. 1706 // 1707 assert( keyInfo.m_keyDepth > 0 ); 1708 int keyDepth = keyInfo.m_keyDepth; 1709 1710 while (keyDepth > 0) 1711 { 1712 fe = iter.hasNext() ? iter.next() : null; 1713 keyDepth--; 1714 } 1715 } 1716 else 1717 { 1718 keyInfo.addKeyData(fe.m_value); 1719 fe = iter.hasNext() ? iter.next() : null; 1720 } 1721 query.addRange(keyInfo); 1722 1723 // 1724 // The field entry is now positioned to the next field. 1725 // Determine if we have a range. 1726 // 1727 if (fe != null && firstField.equals(fe.m_name) && 1728 isRange(firstOp, fe.m_op)) 1729 { 1730 keyInfo = new KeyInfo(mapComparisonOp(fe.m_op)); 1731 keyInfo.addKeyData(fe.m_value); 1732 query.addRange(keyInfo); 1733 fe = iter.hasNext() ? iter.next() : null; 1734 } 1735 1736 // 1737 // The rest are filters 1738 // 1739 while (fe != null) 1740 { 1741 query.addFilter(createFilterKey(fe)); 1742 fe = iter.hasNext() ? iter.next() : null; 1743 } 1744 1745 return query; 1746 } 1747 1748 private CompiledQuery compileQuery() 1749 { 1750 if (m_hasKeyCoverage) 1751 { 1752 return compileSimpleQuery(); 1753 } 1754 return compileOrderedQuery(CompileFilter.FILTER_LTEGTE); 1755 } 1756 1757 private void createEqualsKey(KeyInfo keyInfo, CompileFilter filter) 1758 { 1759 // 1760 // Normally, a range query is of only one depth; that is, a 1761 // query that does: 1762 // 1763 // part1 > value 1764 // 1765 // will position the start iterator using the first field 1766 // of a key. When multiple fields use ==, we can optimize 1767 // the position by specifying all the fields instead of 1768 // setting the first one, and filtering on the rest. As 1769 // an example: 1770 // 1771 // part1 == v1 && part2 == v2 1772 // 1773 // can be optimized by defining both part1 and part2 in 1774 // the key, and adjusting the depth so the runtime knows 1775 // to look at both of them when positioning the iterator. 1776 // 1777 // The code below iterates over both the FieldDescriptor 1778 // and KeyFieldEntry, and it continues to build a temp list 1779 // of field entries until the field names don't match, or 1780 // an == is not seen. 1781 // 1782 // The runtime supports positioning of >= and <=, so we also 1783 // allow one of these. But once one is ecountered, the processing 1784 // of the fields terminates, any subsequent expressions are filtered. 1785 // 1786 Iterator<FieldDescriptor> fdIter = 1787 m_descriptor.m_fields.iterator(); 1788 Iterator<KeyFieldEntry> feIter = m_entries.iterator(); 1789 ArrayList<KeyFieldEntry> entries = new ArrayList<KeyFieldEntry>(); 1790 1791 int lastOp = keyInfo.m_rop; 1792 1793 while (feIter.hasNext() && fdIter.hasNext()) 1794 { 1795 FieldDescriptor fd = fdIter.next(); 1796 KeyFieldEntry fe = feIter.next(); 1797 1798 if (filter == CompileFilter.FILTER_LTEGTE) 1799 { 1800 if (fd.m_name.equals(fe.m_name) && 1801 fe.m_op == KeyComparisonOperator.EQ) 1802 { 1803 entries.add(fe); 1804 } 1805 else 1806 { 1807 break; 1808 } 1809 } 1810 else 1811 { 1812 assert( filter == CompileFilter.FILTER_NONE ); 1813 if (fd.m_name.equals(fe.m_name) && 1814 (fe.m_op == KeyComparisonOperator.EQ || 1815 fe.m_op == KeyComparisonOperator.GTE || 1816 fe.m_op == KeyComparisonOperator.LTE)) 1817 { 1818 entries.add(fe); 1819 lastOp = mapComparisonOp(fe.m_op); 1820 1821 if (fe.m_op == KeyComparisonOperator.GTE || 1822 fe.m_op == KeyComparisonOperator.LTE) 1823 { 1824 break; 1825 } 1826 } 1827 else 1828 { 1829 break; 1830 } 1831 } 1832 } 1833 1834 // 1835 // Save the last op, which the runtime uses to position the key. 1836 // 1837 keyInfo.m_rop = lastOp; 1838 1839 // 1840 // Using the temp list, build the actual key 1841 // 1842 keyInfo.m_keyDepth = 0; 1843 for (KeyFieldEntry fe : entries) 1844 { 1845 keyInfo.addKeyData(fe.m_value); 1846 keyInfo.m_keyDepth += 1; 1847 } 1848 assert( keyInfo.m_keyDepth > 0 ); 1849 } 1850 1851 private boolean isRange( 1852 KeyComparisonOperator rop1, 1853 KeyComparisonOperator rop2) 1854 { 1855 // 1856 // See if the operators form a "range" of values. 1857 // 1858 if (rop1 == KeyComparisonOperator.GTE || 1859 rop1 == KeyComparisonOperator.GT) 1860 { 1861 if (rop2 == KeyComparisonOperator.LTE || 1862 rop2 == KeyComparisonOperator.LT) 1863 { 1864 return true; 1865 } 1866 } 1867 if (rop2 == KeyComparisonOperator.GTE || 1868 rop2 == KeyComparisonOperator.GT) 1869 { 1870 if (rop1 == KeyComparisonOperator.LTE || 1871 rop1 == KeyComparisonOperator.LT) 1872 { 1873 return true; 1874 } 1875 } 1876 return false; 1877 } 1878 1879 private KeyInfo createFilterKey(KeyFieldEntry fe) 1880 { 1881 // 1882 // Key filters require a complete key with empty field 1883 // values up to the filtered key field. The runtime uses 1884 // keyDepth to determine which field slot to look at. 1885 // 1886 int keyDepth = 0; 1887 int pos = 0; 1888 for (FieldDescriptor fd : m_descriptor.m_fields) 1889 { 1890 if (fd.m_name.equals(fe.m_name)) 1891 { 1892 break; 1893 } 1894 pos += getKeyOffset(fd.getTypeCode()); 1895 keyDepth++; 1896 } 1897 // 1898 // The filter operator is the opposite of the field 1899 // operator (i.e. to find all the EQ keys, we filter on 1900 // all those that are NEQ). 1901 // 1902 KeyComparisonOperator filterOp = getFilterOp(fe.m_op); 1903 KeyInfo keyInfo = new KeyInfo(mapComparisonOp(filterOp)); 1904 1905 // 1906 // Allocate all the data and position it to the field we 1907 // need to set. We add a null byte in a loop instead of 1908 // the position() call to insure that the contents of the 1909 // preceding key data is zero. 1910 // 1911 while (pos > 0) 1912 { 1913 keyInfo.addKeyData((byte)0); 1914 pos--; 1915 } 1916 keyInfo.addKeyData(fe.m_value); 1917 keyInfo.m_keyDepth = keyDepth; 1918 1919 return keyInfo; 1920 } 1921 1922 private KeyComparisonOperator getFilterOp(KeyComparisonOperator op) 1923 { 1924 KeyComparisonOperator filterOp; 1925 1926 if (op == KeyComparisonOperator.GTE) 1927 { 1928 filterOp = KeyComparisonOperator.LT; 1929 } 1930 else if (op == KeyComparisonOperator.GT) 1931 { 1932 filterOp = KeyComparisonOperator.LTE; 1933 } 1934 else if (op == KeyComparisonOperator.LTE) 1935 { 1936 filterOp = KeyComparisonOperator.GT; 1937 } 1938 else if (op == KeyComparisonOperator.LT) 1939 { 1940 filterOp = KeyComparisonOperator.GTE; 1941 } 1942 else if (op == KeyComparisonOperator.NEQ) 1943 { 1944 filterOp = KeyComparisonOperator.EQ; 1945 } 1946 else 1947 { 1948 assert( op == KeyComparisonOperator.EQ ); 1949 filterOp = KeyComparisonOperator.NEQ; 1950 } 1951 return filterOp; 1952 } 1953 1954 private int mapOrderBy(KeyOrderedBy orderBy) 1955 { 1956 return (orderBy == KeyOrderedBy.ASCENDING) 1957 ? SWRBTreeAscending : SWRBTreeDescending; 1958 } 1959 1960 static int mapObjectLock(LockMode objectLock) 1961 { 1962 switch (objectLock) 1963 { 1964 case NOLOCK: 1965 return KeyOptNoLock; 1966 case READLOCK: 1967 return KeyOptReadLock; 1968 } 1969 assert( objectLock == LockMode.WRITELOCK ); 1970 1971 return KeyOptWriteLock; 1972 } 1973 1974 private int mapComparisonOp(KeyComparisonOperator op) 1975 { 1976 switch (op) 1977 { 1978 case NEQ: 1979 return ObjSrv_NEQ; 1980 case GTE: 1981 return ObjSrv_GTE; 1982 case GT: 1983 return ObjSrv_GT; 1984 case LTE: 1985 return ObjSrv_LTE; 1986 case LT: 1987 return ObjSrv_LT; 1988 } 1989 assert( op == KeyComparisonOperator.EQ ); 1990 1991 return ObjSrv_EQ; 1992 } 1993 1994 private T attachObject(LockMode objectLock) 1995 { 1996 T obj = _attachObject( 1997 m_descriptor.m_objDomainId, 1998 m_descriptor.m_objTypeId, 1999 m_descriptor.m_keyDomainId, 2000 m_descriptor.m_keyTypeId, 2001 m_query.m_keyInfo1.array(), 2002 mapObjectLock(objectLock)); 2003 2004 if (obj == null && m_queryScope != null && getDistributedQuery() != null) 2005 { 2006 getDistributedQuery().findObject( 2007 m_queryScope, 2008 m_descriptor.m_objDomainId, 2009 m_descriptor.m_objTypeId, 2010 m_descriptor.m_keyDomainId, 2011 m_descriptor.m_keyTypeId, 2012 m_query.m_keyInfo1.array(), 2013 mapObjectLock(objectLock)); 2014 obj = _attachObject( 2015 m_descriptor.m_objDomainId, 2016 m_descriptor.m_objTypeId, 2017 m_descriptor.m_keyDomainId, 2018 m_descriptor.m_keyTypeId, 2019 m_query.m_keyInfo1.array(), 2020 mapObjectLock(objectLock)); 2021 } 2022 return obj; 2023 } 2024 2025 private T attachMinimum(CompiledQuery query, LockMode objectLock) 2026 { 2027 if (m_queryScope != null && getDistributedQuery() != null) 2028 { 2029 getDistributedQuery().findMinimum( 2030 m_queryScope, 2031 m_descriptor.m_objDomainId, 2032 m_descriptor.m_objTypeId, 2033 m_descriptor.m_keyDomainId, 2034 m_descriptor.m_keyTypeId, 2035 query.m_keyInfo1.m_keyDepth, 2036 query.m_keyInfo1.m_rop, 2037 query.m_keyInfo1.array(), 2038 mapObjectLock(objectLock)); 2039 } 2040 2041 return _attachMinimum( 2042 m_descriptor.m_objDomainId, 2043 m_descriptor.m_objTypeId, 2044 m_descriptor.m_keyDomainId, 2045 m_descriptor.m_keyTypeId, 2046 query.m_keyInfo1.m_keyDepth, 2047 query.m_keyInfo1.m_rop, 2048 query.m_keyInfo1.array(), 2049 mapObjectLock(objectLock)); 2050 } 2051 2052 private T attachMaximum(CompiledQuery query, LockMode objectLock) 2053 { 2054 if (m_queryScope != null && getDistributedQuery() != null) 2055 { 2056 getDistributedQuery().findMaximum( 2057 m_queryScope, 2058 m_descriptor.m_objDomainId, 2059 m_descriptor.m_objTypeId, 2060 m_descriptor.m_keyDomainId, 2061 m_descriptor.m_keyTypeId, 2062 query.m_keyInfo1.m_keyDepth, 2063 query.m_keyInfo1.m_rop, 2064 query.m_keyInfo1.array(), 2065 mapObjectLock(objectLock)); 2066 } 2067 return _attachMaximum( 2068 m_descriptor.m_objDomainId, 2069 m_descriptor.m_objTypeId, 2070 m_descriptor.m_keyDomainId, 2071 m_descriptor.m_keyTypeId, 2072 query.m_keyInfo1.m_keyDepth, 2073 query.m_keyInfo1.m_rop, 2074 query.m_keyInfo1.array(), 2075 mapObjectLock(objectLock)); 2076 } 2077 2078 private T createObject(ArrayList<CreateBuffer> createValues) 2079 { 2080 Object [] cvArray = (createValues == null) 2081 ? null : createValues.toArray(); 2082 return _createObject( 2083 m_descriptor.m_objDomainId, 2084 m_descriptor.m_objTypeId, 2085 m_descriptor.m_keyDomainId, 2086 m_descriptor.m_keyTypeId, 2087 m_query.m_keyInfo1.array(), 2088 cvArray); 2089 } 2090 2091 private native boolean _getKeyDescriptor(KeyDescriptor descriptor); 2092 private native T _attachObject( 2093 int objDomainId, 2094 int objTypeId, 2095 int keyDomainId, 2096 int keyTypeId, 2097 byte [] keyData, 2098 int objLock); 2099 private native T _attachMinimum( 2100 int objDomainId, 2101 int objTypeId, 2102 int keyDomainId, 2103 int keyTypeId, 2104 int keyDepth, 2105 int rop, 2106 byte [] keyData, 2107 int objLock); 2108 private native T _attachMaximum( 2109 int objDomainId, 2110 int objTypeId, 2111 int keyDomainId, 2112 int keyTypeId, 2113 int keyDepth, 2114 int rop, 2115 byte [] keyData, 2116 int objLock); 2117 private native T _createObject( 2118 int objDomainId, 2119 int objTypeId, 2120 int keyDomainId, 2121 int keyTypeId, 2122 byte [] keyData, 2123 Object [] createValues); 2124}