1 21 22 package org.apache.derby.iapi.types; 23 24 26 import org.apache.derby.iapi.services.sanity.SanityManager; 27 28 import org.apache.derby.iapi.error.StandardException; 29 import org.apache.derby.iapi.reference.SQLState; 30 31 import java.text.CollationElementIterator ; 32 import java.text.Collator ; 33 import java.text.RuleBasedCollator ; 34 import java.util.Locale ; 35 36 47 public class Like { 48 private static final char anyChar = '_'; 49 private static final char anyString = '%'; 50 51 private static final String SUPER_STRING = "\uffff"; 52 53 private Like() { } 55 56 69 public static Boolean like 70 ( 71 char[] val, 72 int valLength, 73 char[] pat, 74 int patLength, 75 char[] escape, 76 int escapeLength 77 ) throws StandardException 78 { 79 return like(val, 0, valLength, pat, 0, patLength, escape, escapeLength); 80 } 81 82 97 public static Boolean like 98 ( 99 int[] val, 100 int valLength, 101 int[] pat, 102 int patLength, 103 int[] escape, 104 int escapeLength, 105 RuleBasedCollator collator 106 ) throws StandardException 107 { 108 return like(val, 0, valLength, pat, 0, patLength, escape, escapeLength, collator); 109 } 110 111 112 private static Boolean like 113 ( 114 char[] val, 115 int vLoc, int vEnd, char[] pat, 118 int pLoc, int pEnd, char[] escape, 121 int escapeLength 122 ) throws StandardException 123 { 124 char escChar = ' '; 125 boolean haveEsc = true; 126 127 if (val == null) return null; 128 if (pat == null) return null; 129 130 if (escape == null) 131 { 132 haveEsc = false; 133 } 134 else 135 { 136 escChar = escape[0]; 137 } 138 139 Boolean result; 140 141 while (true) { 142 143 if ((result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd)) != null) 144 { 145 return result; 146 } 147 148 while (pat[pLoc] != anyChar && pat[pLoc] != anyString && 150 ((! haveEsc) || pat[pLoc] != escChar)) { 151 if (val[vLoc] == pat[pLoc]) 152 { 153 vLoc++; pLoc++; 154 155 result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd); 156 if (result != null) 157 return result; 158 } 159 else 160 { 161 return Boolean.FALSE; 162 } 163 } 164 165 if (haveEsc && pat[pLoc] == escChar) { 168 pLoc++; 169 if (pLoc == pEnd) { 170 throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE); 171 } 172 if (pat[pLoc] != escChar && 173 pat[pLoc] != anyChar && 174 pat[pLoc] != anyString) { 175 throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE); 176 } 177 if (val[vLoc] == pat[pLoc]) { 179 vLoc++; pLoc++; 180 181 result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd); 182 if (result != null) 183 return result; 184 } 185 else return Boolean.FALSE; 186 } 187 else if (pat[pLoc] == anyChar) { 188 vLoc++; pLoc++; 190 191 result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd); 192 if (result != null) 193 return result; 194 } 195 else if (pat[pLoc] == anyString) { 196 if (pLoc+1 == pEnd) 198 return Boolean.TRUE; 199 200 if (SanityManager.DEBUG) 202 SanityManager.ASSERT(vLoc!=vEnd, 203 "Should have been found already"); 204 205 boolean anys = true; 210 for (int i=pLoc+1;i<pEnd;i++) 211 if (pat[i]!=anyString) { 212 anys=false; 213 break; 214 } 215 if (anys) return Boolean.TRUE; 216 217 222 225 228 int vRem = vEnd - vLoc; 230 231 int n=0; 232 233 int minLen = getMinLen(pat, pLoc+1, pEnd, haveEsc, escChar); 235 for (int i=vRem; i>=minLen; i--) 236 { 237 Boolean restResult = Like.like(val,vLoc+n,vLoc+n+i,pat,pLoc+1,pEnd,escape,escapeLength); 238 if (SanityManager.DEBUG) 239 { 240 if (restResult == null) 241 { 242 String vStr = new String (val,vLoc+n,i); 243 String pStr = new String (pat,pLoc+1,pEnd-(pLoc+1)); 244 SanityManager.THROWASSERT("null result on like(value = "+vStr+", pat = "+pStr+")"); 245 } 246 } 247 if (restResult.booleanValue()) 248 return restResult; 249 250 n++; 251 } 252 return Boolean.FALSE; 254 } 255 } 256 } 257 258 259 private static Boolean like 260 ( 261 int[] val, 262 int vLoc, int vEnd, int[] pat, 265 int pLoc, int pEnd, int[] escape, 268 int escapeLength, 269 RuleBasedCollator collator 270 ) throws StandardException 271 { 272 int[] escCharInts = null; 273 boolean haveEsc = true; 274 int[] anyCharInts = new int[1]; int[] anyStringInts = new int[1]; 277 if (val == null) return null; 278 if (pat == null) return null; 279 280 if (escape == null) 281 { 282 haveEsc = false; 283 } 284 else 285 { 286 escCharInts = escape; 287 } 288 289 Boolean result; 290 291 CollationElementIterator cei = 293 collator.getCollationElementIterator("_"); 294 anyCharInts[0] = cei.next(); 295 { 296 int nextInt; 297 298 while ((nextInt = cei.next()) != CollationElementIterator.NULLORDER) 300 { 301 int[] temp = new int[anyCharInts.length + 1]; 302 for (int index = 0; index < anyCharInts.length; index++) 303 { 304 temp[index] = anyCharInts[index]; 305 } 306 temp[anyCharInts.length] = nextInt; 307 anyCharInts = temp; 308 } 309 } 310 cei = collator.getCollationElementIterator("%"); 312 anyStringInts[0] = cei.next(); 313 { 314 int nextInt; 315 316 while ((nextInt = cei.next()) != CollationElementIterator.NULLORDER) 318 { 319 int[] temp = new int[anyStringInts.length + 1]; 320 for (int index = 0; index < anyStringInts.length; index++) 321 { 322 temp[index] = anyStringInts[index]; 323 } 324 temp[anyStringInts.length] = nextInt; 325 anyStringInts = temp; 326 } 327 } 328 329 while (true) 330 { 331 result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd, anyStringInts); 333 if (result != null) 334 return result; 335 336 while ( (! matchSpecial(pat, pLoc, pEnd, anyCharInts)) && 338 (! matchSpecial(pat, pLoc, pEnd, anyStringInts)) && 339 ((! haveEsc) 340 || (! matchSpecial(pat, pLoc, pEnd, escCharInts)))) 341 { 342 if (val[vLoc] == pat[pLoc]) 343 { 344 vLoc++; pLoc++; 345 346 result = checkLengths(vLoc, vEnd, pLoc, 347 pat, pEnd, anyStringInts); 348 if (result != null) 349 { 350 return result; 351 } 352 } 353 else 354 { 355 return Boolean.FALSE; 356 } 357 } 358 359 if (haveEsc && matchSpecial(pat, pLoc, pEnd, escCharInts)) 362 { 363 pLoc += escCharInts.length; 364 if (pLoc == pEnd) 365 { 366 throw StandardException.newException( 367 SQLState.LANG_INVALID_ESCAPE_SEQUENCE); 368 } 369 370 int[] specialInts = null; 371 if (matchSpecial(pat, pLoc, pEnd, escCharInts)) 372 { 373 specialInts = escCharInts; 374 } 375 if (matchSpecial(pat, pLoc, pEnd, anyCharInts)) 376 { 377 specialInts = anyCharInts; 378 } 379 if (matchSpecial(pat, pLoc, pEnd, anyStringInts)) 380 { 381 specialInts = anyStringInts; 382 } 383 if (specialInts == null) 384 { 385 throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE); 386 } 387 for (int index = 0; index < specialInts.length; index++) 389 { 390 if (val[vLoc + index] != pat[pLoc + index]) 391 { 392 return Boolean.FALSE; 393 } 394 } 395 396 vLoc += specialInts.length; 397 pLoc += specialInts.length; 398 399 result = checkLengths(vLoc, vEnd, 401 pLoc, pat, pEnd, anyStringInts); 402 403 if (result != null) 404 return result; 405 } 406 else if (matchSpecial(pat, pLoc, pEnd, anyCharInts)) 407 { 408 vLoc += anyCharInts.length; 410 pLoc += anyCharInts.length; 411 412 result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd, anyStringInts); 413 if (result != null) 414 return result; 415 } 416 else if (matchSpecial(pat, pLoc, pEnd, anyStringInts)) 417 { 418 if (pLoc+1 == pEnd) 420 return Boolean.TRUE; 421 422 if (SanityManager.DEBUG) 424 SanityManager.ASSERT(vLoc!=vEnd, 425 "Should have been found already"); 426 427 if (vLoc == vEnd) 428 return Boolean.TRUE; 429 430 boolean allPercentChars = true; 434 for (int i=pLoc+1;i<pEnd;i++) 435 { 436 if (! matchSpecial(pat, i, pEnd, anyStringInts)) 437 { 438 allPercentChars=false; 439 break; 440 } 441 } 442 if (allPercentChars) 443 return Boolean.TRUE; 444 445 450 453 456 int vRem = vEnd - vLoc; 458 459 int n=0; 460 461 int minLen = getMinLen(pat, pLoc+1, pEnd, haveEsc, escCharInts, anyStringInts); 463 for (int i=vRem; i>=minLen; i--) 464 { 465 Boolean restResult = Like.like(val,vLoc+n,vLoc+n+i,pat,pLoc+1,pEnd,escape,escapeLength, collator); 466 if (SanityManager.DEBUG) 467 { 468 if (restResult == null) 469 { 470 SanityManager.THROWASSERT("null result on like(vLoc+n = "+(vLoc+n)+", i = "+i+ 471 ", pLoc+1 = " + (pLoc+1) + ", pEnd-(pLoc+1) = " + 472 (pEnd-(pLoc+1)) + ")"); 473 } 474 } 475 if (restResult.booleanValue()) 476 return restResult; 477 478 n++; 479 } 480 return Boolean.FALSE; 482 } 483 } 484 } 485 486 489 static int getMinLen(char[] pattern, int pStart, int pEnd, boolean haveEsc, char escChar) 490 { 491 int m=0; 492 for (int l = pStart; l<pEnd; ) 493 { 494 if (haveEsc && pattern[l] == escChar) { l+=2; 496 m++; 497 } 498 else if (pattern[l] == anyString) { 499 l++; } 501 else { l++; m++; 503 } 504 } 505 return m; 506 } 507 508 511 static int getMinLen(int[] pattern, int pStart, int pEnd, boolean haveEsc, 512 int[] escCharInts, int[] anyStringInts) 513 { 514 int m=0; 515 for (int l = pStart; l<pEnd; ) 516 { 517 if (haveEsc && matchSpecial(pattern, l, pEnd, escCharInts)) 518 { 519 l += escCharInts.length + 1; 520 m += escCharInts.length; 521 } 522 else if (matchSpecial(pattern, l, pEnd, anyStringInts)) 523 { 524 l += anyStringInts.length; } 526 else 527 { l++; m++; 529 } 530 } 531 return m; 532 } 533 534 547 548 static Boolean checkLengths(int vLoc, int vEnd, 549 int pLoc, char[] pat, int pEnd) 550 { 551 if (vLoc == vEnd) 552 { 553 if (pLoc == pEnd) 554 { 555 return Boolean.TRUE; 556 } 557 else 558 { 559 for (int i=pLoc; i<pEnd; i++) 561 { 562 if (pat[i] != anyString) 563 { 564 return Boolean.FALSE; } 566 } 567 return Boolean.TRUE; 568 } 569 } 570 else if (pLoc == pEnd) 571 { 572 return Boolean.FALSE; } 574 else return null; } 576 577 590 591 static Boolean checkLengths(int vLoc, int vEnd, 592 int pLoc, int[] pat, int pEnd, int[] anyStringInts) 593 { 594 if (vLoc == vEnd) 595 { 596 if (pLoc == pEnd) 597 { 598 return Boolean.TRUE; 599 } 600 else 601 { 602 for (int i=pLoc; i<pEnd; i += anyStringInts.length) 604 { 605 if (! matchSpecial(pat, i, pEnd, anyStringInts)) 606 { 607 return Boolean.FALSE; 608 } 609 } 610 return Boolean.TRUE; 611 } 612 } 613 else if (pLoc == pEnd) 614 { 615 return Boolean.FALSE; } 617 else return null; } 619 620 626 627 private static boolean matchSpecial(int[] pat, int patStart, int patEnd, int[] specialInts) 628 { 629 if (specialInts.length > patEnd - patStart) 634 return false; 635 if (specialInts.length <= patEnd - patStart) 636 { 637 for (int index = 0; index < specialInts.length; index++) 638 { 639 if (pat[patStart + index] != specialInts[index]) 640 { 641 return false; } 643 } 644 } 645 return true; 646 } 647 648 649 652 public static Boolean like(char[] value, int valueLength, char[] pattern, int patternLength) throws StandardException { 653 if (value == null || pattern == null) return null; 654 return like(value, valueLength, pattern, patternLength, null, 0); 655 } 656 657 660 public static Boolean like(int[] value, int valueLength, int[] pattern, int patternLength, RuleBasedCollator collator) 661 throws StandardException 662 { 663 if (value == null || pattern == null) return null; 664 return like(value, valueLength, pattern, patternLength, null, 0, collator); 665 } 666 667 669 678 679 public static boolean isOptimizable(String pattern) 680 { 681 if (pattern == null) 682 { 683 return false; 684 } 685 686 if (pattern.length() == 0) { 687 return true; 688 } 689 690 char firstChar = pattern.charAt(0); 692 693 return (firstChar != anyChar && firstChar != anyString); 694 } 695 696 public static String greaterEqualStringFromParameter(String pattern, int maxWidth) 697 throws StandardException { 698 699 if (pattern == null) 700 return null; 701 702 return greaterEqualString(pattern, (String ) null, maxWidth); 703 } 704 705 public static String greaterEqualStringFromParameterWithEsc(String pattern, String escape, int maxWidth) 706 throws StandardException { 707 708 if (pattern == null) 709 return null; 710 711 return greaterEqualString(pattern, escape, maxWidth); 712 } 713 714 723 public static String greaterEqualString(String pattern, String escape, int maxWidth) 724 throws StandardException 725 { 726 727 int firstAnyChar = pattern.indexOf(anyChar); 728 int firstAnyString = pattern.indexOf(anyString); 729 730 736 if ((escape != null) && (escape.length() != 0)) 737 { 738 char escChar = escape.charAt(0); 739 if (pattern.indexOf(escChar) != -1) 740 { 741 744 return padWithNulls(greaterEqualString(pattern, escChar), maxWidth); 745 } 746 } 748 749 if (firstAnyChar == -1) 750 { 751 if (firstAnyString != -1) { 753 pattern = pattern.substring(0, firstAnyString); 754 } 755 } 756 else if (firstAnyString == -1) 757 { 758 pattern = pattern.substring(0, firstAnyChar); 759 } 760 else 761 { 762 pattern = pattern.substring(0, (firstAnyChar > firstAnyString) ? 763 firstAnyString : 764 firstAnyChar); 765 } 766 return padWithNulls(pattern, maxWidth); 767 } 768 769 776 777 private static String greaterEqualString(String pattern, char escChar) 778 throws StandardException 779 { 780 int patternLen = pattern.length(); 781 char[] patternChars = new char[patternLen]; 782 char[] result = new char[patternLen]; 783 pattern.getChars(0, patternLen, patternChars, 0); 784 785 int r = 0; 786 for (int p = 0; p < patternLen && r < patternLen; p++) 787 { 788 char c = patternChars[p]; 789 if (c == escChar) 790 { 791 p++; 793 if (p >= patternLen) 795 throw StandardException.newException( 796 SQLState.LANG_INVALID_ESCAPE_SEQUENCE); 797 result[r++] = patternChars[p]; 798 continue; 799 } 800 801 if (c == anyChar || c == anyString) 803 { 804 return new String (result, 0, r); 805 } 806 807 result[r++] = patternChars[p]; 808 } 809 810 return new String (result, 0, r); 812 } 813 814 823 824 public static String 825 stripEscapesNoPatternChars(String pattern, char escChar) 826 throws StandardException 827 { 828 int patternLen = pattern.length(); 829 char[] patternChars = new char[patternLen]; 830 char[] result = new char[patternLen]; 831 pattern.getChars(0, patternLen, patternChars, 0); 832 833 int r = 0; 834 for (int p = 0; p < patternLen && r < patternLen; p++) 835 { 836 char c = pattern.charAt(p); 837 if (c == escChar) 838 { 839 p++; 841 if (p >= patternLen) 843 throw StandardException.newException( 844 SQLState.LANG_INVALID_ESCAPE_SEQUENCE); 845 result[r++] = patternChars[p]; 846 continue; 847 } 848 849 if (c == anyChar || c == anyString) 851 { 852 return null; 853 } 854 855 result[r++] = patternChars[p]; 856 } 857 return new String (result, 0, r); 858 } 859 860 public static String lessThanStringFromParameter(String pattern, int maxWidth) 861 throws StandardException 862 { 863 if (pattern == null) 864 return null; 865 return lessThanString(pattern, null, maxWidth); 866 } 867 868 public static String lessThanStringFromParameterWithEsc(String pattern, String escape, int maxWidth) 869 throws StandardException 870 { 871 if (pattern == null) 872 return null; 873 return lessThanString(pattern, escape, maxWidth); 874 } 875 876 886 public static String lessThanString(String pattern, String escape, int maxWidth) 887 throws StandardException 888 { 889 int lastUsableChar; 890 char oldLastChar; 891 char newLastChar; 892 final int escChar; 893 894 if ((escape != null) && (escape.length() !=0)) 895 { 896 escChar = escape.charAt(0); 897 } 898 else { 899 escChar = -1; 902 } 903 904 916 917 StringBuffer upperLimit = new StringBuffer (maxWidth); 918 919 for (int i = 0; i < pattern.length(); i++) { 921 char c = pattern.charAt(i); 922 if (c == escChar) { 923 if (++i >= pattern.length()) { 924 throw StandardException.newException( 925 SQLState.LANG_INVALID_ESCAPE_SEQUENCE); 926 } 927 c = pattern.charAt(i); 928 } else if (c == anyChar || c == anyString) { 929 break; 930 } 931 upperLimit.append(c); 932 } 933 934 if (upperLimit.length() == 0) { 936 return SUPER_STRING; 937 } 938 939 lastUsableChar = upperLimit.length() - 1; 941 oldLastChar = upperLimit.charAt(lastUsableChar); 942 newLastChar = oldLastChar; 943 newLastChar++; 944 945 if (newLastChar < oldLastChar) 947 { 948 return SUPER_STRING; 949 } 950 951 upperLimit.setCharAt(lastUsableChar, newLastChar); 952 953 if (upperLimit.length() < maxWidth) { 955 upperLimit.setLength(maxWidth); 956 } 957 958 return upperLimit.toString(); 959 } 960 961 971 public static boolean isLikeComparisonNeeded(String pattern) 972 { 973 int firstAnyChar = pattern.indexOf(anyChar); 974 int firstAnyString = pattern.indexOf(anyString); 975 976 if (SanityManager.DEBUG) 977 { 978 SanityManager.ASSERT(pattern.length() != 0, 979 "pattern expected to be non-zero length"); 980 } 981 982 if (firstAnyChar == -1 && firstAnyString == -1) 984 return false; 985 986 987 if (firstAnyChar != -1) 988 { 989 return true; 990 } 991 992 995 if (firstAnyString != pattern.length() - 1) 996 { 997 return true; 998 } 999 1000 return false; 1001 } 1002 1003 1011 private static String padWithNulls(String string, int len) 1012 { 1013 if(string.length() >= len) 1014 return string; 1015 1016 StringBuffer buf = new StringBuffer (len).append(string); 1017 buf.setLength(len); 1018 1019 return buf.toString(); 1020 } 1021} 1022 | Popular Tags |