Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / iapi / types / Like.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/iapi/types/Like.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/iapi/types/Like.java
new file mode 100644 (file)
index 0000000..32a4655
--- /dev/null
@@ -0,0 +1,739 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.iapi.types.Like\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.types;\r
+\r
+// RESOLVE: MOVE THIS CLASS TO PROTOCOL (See LikeOperatorNode)\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import java.text.CollationElementIterator;\r
+import java.text.Collator;\r
+import java.text.RuleBasedCollator;\r
+import java.util.Locale;\r
+\r
+/**\r
+       Like matching algorithm. Not too speedy for %s.\r
+\r
+       SQL92 says the escape character can only and must be followed\r
+       by itself, %, or _.  So if you choose % or _ as the escape character,\r
+       you can no longer do that sort of matching.\r
+\r
+       Not the most recent Like -- missing the unit tests\r
+\r
+ */\r
+public class Like {\r
+       private static final char anyChar = '_';\r
+       private static final char anyString = '%';\r
+\r
+       private static final String SUPER_STRING = "\uffff";\r
+\r
+       private Like() { // do not instantiate\r
+       }\r
+\r
+       /**\r
+         \r
+        This method gets called for UCS_BASIC and territory based character\r
+        string types to look for a pattern in a value string. It also deals\r
+        with escape character if user has provided one.\r
+         \r
+               @param val value to compare. if null, result is null.\r
+               @param valLength length of val\r
+               @param pat pattern to compare. if null, result is null.\r
+               @param patLength length of pat\r
+               @param escape escape character. Must be 1 char long.\r
+                       if null, no escape character is used.\r
+               @param escapeLength length of escape\r
+               @param collator null if we are dealing with UCS_BASIC \r
+                   character string types. If not null, then we use it to \r
+                   get collation elements for characters in val and \r
+                   non-metacharacters in pat to do the comparison.\r
+\r
+               @return null if val or pat null, otherwise true if match\r
+               and false if not.\r
+               @exception StandardException thrown if data invalid\r
+        */\r
+       public static Boolean like\r
+       (\r
+               char[]  val, \r
+               int     valLength, \r
+               char[]  pat, \r
+               int     patLength, \r
+               char[]  escape,\r
+               int     escapeLength,\r
+               RuleBasedCollator collator\r
+       ) throws StandardException \r
+       {\r
+               return like(val, 0, valLength, pat, 0, patLength, escape, \r
+                               escapeLength, collator);\r
+       }\r
+\r
+       /* For character string types with UCS_BASIC and territory based\r
+        * collation. */\r
+       private static Boolean like\r
+       (\r
+               char[]  val, \r
+               int     vLoc,   // start at val[vLoc]\r
+               int     vEnd,   // end at val[vEnd]\r
+               char[]  pat, \r
+               int     pLoc,   // start at pat[pLoc]\r
+               int     pEnd,   // end at pat[pEnd]\r
+               char[]  escape,\r
+               int     escapeLength,\r
+               RuleBasedCollator collator\r
+       ) throws StandardException \r
+       {\r
+               char escChar = ' ';\r
+               boolean haveEsc = true;\r
+               \r
+               if (val == null) return null;\r
+               if (pat == null) return null;\r
+\r
+               if (escape == null)\r
+               {\r
+                       haveEsc = false;\r
+               }\r
+               else\r
+               {\r
+                       escChar = escape[0];\r
+               }\r
+\r
+               Boolean result;\r
+\r
+               while (true) {\r
+\r
+                       if ((result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd)) != null) \r
+                       {\r
+                               return result;\r
+                       }\r
+\r
+                       // go until we get a special char in the pattern or hit EOS\r
+                       while (pat[pLoc] != anyChar && pat[pLoc] != anyString &&\r
+                                       ((! haveEsc) || pat[pLoc] != escChar)) {\r
+                               if (checkEquality(val, vLoc, pat, pLoc, collator)) {\r
+                                       vLoc++; pLoc++;\r
+                                       \r
+                                       result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd);\r
+                                       if (result != null) \r
+                                               return result;\r
+                               } else\r
+                                       return Boolean.FALSE;\r
+                       }\r
+\r
+                       // deal with escChar first, as it can be escaping a special char\r
+                       // and can be a special char itself.\r
+                       if (haveEsc && pat[pLoc] == escChar) {\r
+                               pLoc++;\r
+                               if (pLoc == pEnd) {\r
+                                       throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);\r
+                               }\r
+                               if (pat[pLoc] != escChar &&\r
+                                   pat[pLoc] != anyChar &&\r
+                                   pat[pLoc] != anyString) {\r
+                                       throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);\r
+                               }\r
+                               // regardless of the char in pat, it must match exactly:\r
+                               if (checkEquality(val, vLoc, pat, pLoc, collator)) {\r
+                                       vLoc++; pLoc++;\r
+       \r
+                                       result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd);\r
+                                       if (result != null) \r
+                                               return result;\r
+                               }\r
+                               else return Boolean.FALSE;\r
+                       }\r
+                       else if (pat[pLoc] == anyChar) {\r
+                               // regardless of the char, it matches\r
+                               vLoc++; pLoc++;\r
+       \r
+                               result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd);\r
+                               if (result != null) \r
+                                       return result;\r
+                       }\r
+                       else if (pat[pLoc] == anyString) {\r
+                               // catch the simple cases -- end of the pattern or of the string\r
+                               if (pLoc+1 == pEnd)\r
+                                       return Boolean.TRUE;\r
+\r
+                               // would return true, but caught in checkLengths above\r
+                               if (SanityManager.DEBUG)\r
+                                       SanityManager.ASSERT(vLoc!=vEnd, \r
+                                               "Should have been found already");\r
+\r
+                               //if (vLoc == vEnd) // caught in checkLengths\r
+                                       //return Boolean.TRUE;\r
+                               // check if remainder of pattern is anyString's\r
+                               // if escChar == anyString, we couldn't be here\r
+                               boolean anys = true;\r
+                               for (int i=pLoc+1;i<pEnd;i++)\r
+                                       if (pat[i]!=anyString) {\r
+                                               anys=false;\r
+                                               break;\r
+                                       }\r
+                               if (anys) return Boolean.TRUE;\r
+\r
+                               // pattern can match 0 or more chars in value.\r
+                               // to test that, we take the remainder of pattern and\r
+                               // apply it to ever-shorter  remainders of value until\r
+                               // we hit a match.\r
+\r
+                               // the loop never continues from this point -- we will\r
+                               // always generate an answer here.\r
+\r
+                               // REMIND: there are smarter ways to pick the remainders\r
+                               // and do this matching.\r
+\r
+                               // num chars left in value includes current char\r
+                               int vRem = vEnd - vLoc;\r
+\r
+                               int n=0;\r
+\r
+                               // num chars left in pattern excludes the anychar\r
+                               int minLen = getMinLen(pat, pLoc+1, pEnd, haveEsc, escChar);\r
+                               for (int i=vRem; i>=minLen; i--) \r
+                               {\r
+                                       Boolean restResult = Like.like(val, vLoc+n, vLoc+n+i, pat,\r
+                                                       pLoc+1, pEnd, escape, escapeLength, collator);\r
+                                       if (SanityManager.DEBUG)\r
+                                       {\r
+                                               if (restResult == null)\r
+                                               {\r
+                                                       String vStr = new String(val,vLoc+n,i);\r
+                                                       String pStr = new String(pat,pLoc+1,pEnd-(pLoc+1));\r
+                                                       SanityManager.THROWASSERT("null result on like(value = "+vStr+", pat = "+pStr+")");\r
+                                               }\r
+                                       }\r
+                                       if (restResult.booleanValue())\r
+                                               return restResult;\r
+\r
+                                       n++;\r
+                               }\r
+                               // none of the possibilities worked \r
+                               return Boolean.FALSE;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * If the character in val matches the character in pat, then it does not\r
+        * matter if the database is UCS_BASIC or territory based, we simply return \r
+        * TRUE from the method. \r
+        * If the characters do not match and we are running with UCS_BASIC \r
+        * collation, then we will return FALSE. \r
+        * But if the database is territory based, then we want to use the Collator \r
+        * for the territory to determine if the Collator treats the 2 characters \r
+        * as equal (ie if their collation elements match, then the 2 characters \r
+        * are equal even if they  are not the same character).\r
+        * \r
+        * @param val value to compare.\r
+        * @param vLoc character position in val.\r
+        * @param pat pattern to look for in val.\r
+        * @param pLoc character position in pat.\r
+        * @param collator null if we are dealing with UCS_BASIC character string\r
+        *   types. If not null, then we use it to determine the equality of the\r
+        *   2 characters in pat and val if they are not same.\r
+        * @return TRUE if the character in val and vLoc match based on straight\r
+        *   equality or collation element based equality. Otherwise we will \r
+        *   return FALSE.\r
+        */\r
+       private static boolean checkEquality(char[] val, int vLoc,\r
+                       char[] pat, int pLoc, RuleBasedCollator collator) {\r
+\r
+               if (val[vLoc] == pat[pLoc]) { \r
+               // same character, so two strings consisting of this \r
+               // single character must be equal regardless of territory \r
+               return true; \r
+           } else if (collator == null) { \r
+               // not same character, must be unequal in UCS_BASIC \r
+               return false; \r
+           } \r
+\r
+               //Check if the Collator for this database's territory considers these\r
+               //2 characters as equal based on their collation elements\r
+           String s1 = new String(val, vLoc, 1); \r
+           String s2 = new String(pat, pLoc, 1); \r
+\r
+           return collator.compare(s1, s2) == 0; \r
+       }\r
+\r
+       /**\r
+               Calculate the shortest length string that could match this pattern\r
+        */\r
+       static int getMinLen(char[] pattern, int pStart, int pEnd, boolean haveEsc, char escChar) \r
+       {\r
+               int m=0;\r
+               for (int l = pStart; l<pEnd; ) \r
+               {\r
+                       if (haveEsc && pattern[l] == escChar) { // need one char\r
+                               l+=2;\r
+                               m++;\r
+                       }\r
+                       else if (pattern[l] == anyString) {\r
+                               l++; // anyString, nothing needed\r
+                       }\r
+                       else { // anyChar or other chars, need one char\r
+                               l++; m++;\r
+                       }\r
+               }\r
+               return m;\r
+       }\r
+\r
+       /**\r
+        * checkLengths  \r
+        *\r
+        * Returns null if we are not done.\r
+        * Returns true if we are at the end of our value and pattern\r
+        * Returns false if there is more pattern left but out of input value\r
+        *\r
+        * @param vLoc current index into char[] val\r
+        * @param vEnd end index or our value\r
+        * @param pLoc current index into our char[] pattern\r
+        * @param pat  pattern char []\r
+        * @param pEnd end index of our pattern []\r
+        */\r
+\r
+       static Boolean checkLengths(int vLoc, int vEnd,\r
+                       int pLoc, char[] pat, int pEnd) \r
+       {\r
+               if (vLoc == vEnd) \r
+               {\r
+                       if (pLoc == pEnd) \r
+                       {\r
+                               return Boolean.TRUE;\r
+                       }\r
+                       else \r
+                       {\r
+                               // if remainder of pattern is anyString chars, ok\r
+                               for (int i=pLoc; i<pEnd; i++) \r
+                               {\r
+                                       if (pat[i] != anyString)\r
+                                       {\r
+                                               return Boolean.FALSE; // more to match\r
+                                       }\r
+                               }\r
+                               return Boolean.TRUE;\r
+                       }\r
+               }\r
+               else if (pLoc == pEnd)\r
+               {\r
+                       return Boolean.FALSE; // ran out of pattern\r
+               }\r
+               else return null; // still have strings to match, not done\r
+       }\r
+\r
+       /**\r
+        * matchSpecial\r
+        *\r
+        *      check the pattern against the various special character arrays.\r
+        *  The array can be anyStringInts, anyCharInts or anyEscChars (always 1)\r
+        */\r
+\r
+       private static boolean matchSpecial(int[] pat, int patStart, int patEnd, int[] specialInts)\r
+       {\r
+               //\r
+               // multi-collation units per char can exceed the pattern length\r
+               // and we fall around the 2nd if statement and falsely return true.\r
+               //\r
+               if (specialInts.length > patEnd - patStart)\r
+                   return false;\r
+               if (specialInts.length <= patEnd - patStart)\r
+               {\r
+                       for (int index = 0; index < specialInts.length; index++)\r
+                       {\r
+                               if (pat[patStart + index] != specialInts[index])\r
+                               {\r
+                                       return false; // more to match\r
+                               }\r
+                       }\r
+               }\r
+               return true;\r
+       }\r
+\r
+       /*\r
+               Most typical interface for character string types with UCS_BASIC and \r
+               territory based collation.\r
+        */\r
+       public static Boolean like(char[] value, int valueLength, char[] pattern, \r
+                       int patternLength, RuleBasedCollator collator) \r
+       throws StandardException { \r
+               if (value == null || pattern == null) return null;\r
+               return like(value, valueLength, pattern, patternLength, null, 0, \r
+                               collator);\r
+       }\r
+\r
+       // Methods for LIKE transformation at preprocess time:\r
+\r
+       /**\r
+        * Determine whether or not this LIKE can be transformed into optimizable\r
+        * clauses.  It can if the pattern is non-null and if the length == 0 or\r
+        * the first character is not a wild card.\r
+        *\r
+        * @param pattern       The right side of the LIKE\r
+        *\r
+        * @return      Whether or not the LIKE can be transformed\r
+        */\r
+\r
+       public static boolean isOptimizable(String pattern)\r
+       {\r
+               if (pattern == null)\r
+               {\r
+                       return false;\r
+               }\r
+\r
+        if (pattern.length() == 0) {\r
+            return true;\r
+        }\r
+\r
+               // if we have pattern matching at start of string, no optimization\r
+               char firstChar = pattern.charAt(0);\r
+\r
+               return (firstChar != anyChar && firstChar != anyString);\r
+       }\r
+\r
+       public static String greaterEqualStringFromParameter(String pattern, int maxWidth)\r
+               throws StandardException {\r
+\r
+               if (pattern == null)\r
+                       return null;\r
+\r
+               return greaterEqualString(pattern, (String) null, maxWidth);\r
+       }\r
+\r
+       public static String greaterEqualStringFromParameterWithEsc(String pattern, String escape, int maxWidth)\r
+               throws StandardException {\r
+\r
+               if (pattern == null)\r
+                       return null;\r
+\r
+               return greaterEqualString(pattern, escape, maxWidth);\r
+       }\r
+\r
+       /**\r
+        * Return the substring from the pattern for the optimization >= clause.\r
+        *\r
+        * @param pattern       The right side of the LIKE\r
+        * @param escape        The escape clause\r
+        * @param maxWidth      Maximum length of column, for null padding\r
+        *\r
+        * @return      The String for the >= clause\r
+        */\r
+       public static String greaterEqualString(String pattern, String escape, int maxWidth)\r
+           throws StandardException\r
+       {\r
+\r
+               int firstAnyChar = pattern.indexOf(anyChar);\r
+               int firstAnyString = pattern.indexOf(anyString);\r
+\r
+               // \r
+               // For Escape we don't utilize any of the stylish code\r
+               // below but brute force walk the pattern to find out\r
+               // what is there, while stripping escapes\r
+               //\r
+\r
+               if ((escape != null) && (escape.length() != 0))\r
+               {\r
+                       char escChar = escape.charAt(0);\r
+                       if (pattern.indexOf(escChar) != -1)\r
+                       {\r
+                               // we return a string stripping out the escape char\r
+                               // leaving the _? in place as normal chars.\r
+                \r
+                               return padWithNulls(greaterEqualString(pattern, escChar), maxWidth);\r
+                       }\r
+                       // drop through if no escape found\r
+               }\r
+\r
+               if (firstAnyChar == -1)\r
+               {\r
+                       if (firstAnyString != -1) // no _, found %\r
+                       {\r
+                               pattern = pattern.substring(0, firstAnyString);\r
+                       }\r
+               }\r
+               else if (firstAnyString == -1)\r
+               {\r
+                       pattern = pattern.substring(0, firstAnyChar);\r
+               }\r
+               else\r
+               {\r
+                       pattern = pattern.substring(0, (firstAnyChar > firstAnyString) ? \r
+                                                                                       firstAnyString :\r
+                                                                                       firstAnyChar);\r
+               }\r
+               return padWithNulls(pattern, maxWidth);\r
+       }\r
+\r
+    /** \r
+     *  greaterEqualString -- for Escape clause only\r
+     *  \r
+     *  Walk the pattern character by character\r
+     *  @param pattern like pattern to build from\r
+     *  @param escChar the escape character in the pattern\r
+     */\r
+\r
+       private static String greaterEqualString(String pattern, char escChar)\r
+               throws StandardException\r
+       {\r
+               int patternLen = pattern.length();\r
+               char[] patternChars = new char[patternLen];\r
+               char[] result = new char[patternLen];\r
+               pattern.getChars(0, patternLen, patternChars, 0);\r
+\r
+               int r = 0;\r
+               for (int p = 0; p < patternLen && r < patternLen; p++)\r
+               {\r
+            char c = patternChars[p];\r
+                   if (c == escChar)\r
+                       {\r
+                               p++;            // don't copy the escape char\r
+\r
+                               // run out?\r
+                               if (p >= patternLen)\r
+                                       throw StandardException.newException(\r
+                                                       SQLState.LANG_INVALID_ESCAPE_SEQUENCE);\r
+                               result[r++] = patternChars[p];\r
+                               continue;\r
+                       }\r
+\r
+                       // stop on first pattern matching char\r
+                       if (c == anyChar || c == anyString)\r
+                       {\r
+                               return new String(result, 0, r);\r
+                       }\r
+\r
+                       result[r++] = patternChars[p];\r
+               }\r
+\r
+        // no pattern chars\r
+               return new String(result, 0, r);\r
+       }\r
+\r
+       /**\r
+        * stripEscapesNoPatternChars\r
+        *\r
+        * @param pattern       pattern String to search\r
+        * @param escChar       the escape character\r
+        *\r
+        * @return a stripped of ESC char string if no pattern chars, null otherwise\r
+        * @exception StandardException thrown if data invalid\r
+        */\r
+\r
+       public static String\r
+        stripEscapesNoPatternChars(String pattern, char escChar)\r
+               throws StandardException\r
+       {\r
+               int patternLen = pattern.length();\r
+               char[] patternChars = new char[patternLen];\r
+               char[] result = new char[patternLen];\r
+               pattern.getChars(0, patternLen, patternChars, 0);\r
+\r
+               int r = 0;\r
+               for (int p = 0; p < patternLen && r < patternLen; p++)\r
+               {\r
+                       char c = pattern.charAt(p);\r
+                   if (c == escChar)\r
+                       {\r
+                               p++;            // don't copy the escape char\r
+\r
+                               // run out?\r
+                               if (p >= patternLen)\r
+                                       throw StandardException.newException(\r
+                                                       SQLState.LANG_INVALID_ESCAPE_SEQUENCE);\r
+                               result[r++] = patternChars[p];\r
+                               continue;\r
+                       }\r
+\r
+                       // die on first pattern matching char\r
+                       if (c == anyChar || c == anyString)\r
+                       {\r
+                               return null;\r
+                       }\r
+\r
+                       result[r++] = patternChars[p];\r
+               }\r
+               return new String(result, 0, r);\r
+       }\r
+\r
+       public static String lessThanStringFromParameter(String pattern, int maxWidth)\r
+               throws StandardException \r
+       {\r
+               if (pattern == null)\r
+                       return null;\r
+               return lessThanString(pattern, null, maxWidth);\r
+       }\r
+\r
+       public static String lessThanStringFromParameterWithEsc(String pattern, String escape, int maxWidth)\r
+               throws StandardException\r
+       {\r
+               if (pattern == null)\r
+                       return null;\r
+               return lessThanString(pattern, escape, maxWidth);\r
+       }\r
+\r
+       /**\r
+        * Return the substring from the pattern for the < clause.\r
+        *\r
+        * @param pattern       The right side of the LIKE\r
+        * @param escape        The escape clause\r
+        * @param maxWidth      Maximum length of column, for null padding\r
+        *\r
+        * @return      The String for the < clause\r
+        * @exception StandardException thrown if data invalid\r
+        */\r
+       public static String lessThanString(String pattern, String escape, int maxWidth)\r
+               throws StandardException\r
+       {\r
+               int             lastUsableChar;\r
+               char    oldLastChar;\r
+               char    newLastChar;\r
+               final int escChar;\r
+\r
+               if ((escape != null) && (escape.length() !=0))\r
+               {\r
+                       escChar = escape.charAt(0);\r
+               }\r
+               else {\r
+                       // Set escape character to a value outside the char range,\r
+                       // so that comparison with a char always evaluates to false.\r
+                       escChar = -1;\r
+               }\r
+\r
+               /* Find the last non-wildcard character in the pattern\r
+                * and increment it.  In the most common case,\r
+                * "asdf%" becomes "asdg".  However, we need to \r
+                * handle the following:\r
+                *\r
+                *      pattern                 return\r
+                *      -------                 ------\r
+                *      ""                              SUPER_STRING (match against super string)\r
+                *      "%..."                  SUPER_STRING (match against super string)\r
+                *      "_..."                  SUPER_STRING (match against super string)\r
+                *      "asdf%"                 "asdg"\r
+                */\r
+\r
+               StringBuffer upperLimit = new StringBuffer(maxWidth);\r
+\r
+               // Extract the string leading up to the first wildcard.\r
+               for (int i = 0; i < pattern.length(); i++) {\r
+                       char c = pattern.charAt(i);\r
+                       if (c == escChar) {\r
+                               if (++i >= pattern.length()) {\r
+                                       throw StandardException.newException(\r
+                                                       SQLState.LANG_INVALID_ESCAPE_SEQUENCE);\r
+                               }\r
+                               c = pattern.charAt(i);\r
+                       } else if (c == anyChar || c == anyString) {\r
+                               break;\r
+                       }\r
+                       upperLimit.append(c);\r
+               }\r
+\r
+               // Pattern is empty or starts with wildcard.\r
+               if (upperLimit.length() == 0) {\r
+                       return SUPER_STRING;\r
+               }\r
+\r
+               // Increment the last non-wildcard character.\r
+               lastUsableChar = upperLimit.length() - 1;\r
+               oldLastChar = upperLimit.charAt(lastUsableChar);\r
+               newLastChar = oldLastChar;\r
+               newLastChar++;\r
+\r
+               // Check for degenerate roll over\r
+               if (newLastChar < oldLastChar)\r
+               {\r
+                       return SUPER_STRING;\r
+               }\r
+\r
+               upperLimit.setCharAt(lastUsableChar, newLastChar);\r
+\r
+               // Pad the string with nulls.\r
+               if (upperLimit.length() < maxWidth) {\r
+                       upperLimit.setLength(maxWidth);\r
+               }\r
+\r
+               return upperLimit.toString();\r
+       }\r
+       \r
+       /**\r
+        * Return whether or not the like comparison is still needed after\r
+        * performing the like transformation on a constant string.  The\r
+        * comparison is not needed if the constant string is of the form:\r
+        *              CONSTANT%  (constant followed by a trailing %)\r
+        *\r
+        * @param pattern       The right side of the LIKE\r
+        *\r
+        * @return Whether or not the like comparison is still needed.\r
+        */\r
+       public static boolean isLikeComparisonNeeded(String pattern)\r
+       {\r
+               int             firstAnyChar = pattern.indexOf(anyChar);\r
+               int             firstAnyString = pattern.indexOf(anyString);\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(pattern.length() != 0,\r
+                               "pattern expected to be non-zero length");\r
+               }\r
+\r
+               // if no pattern matching characters, no LIKE needed\r
+               if (firstAnyChar == -1 && firstAnyString == -1)\r
+                       return false;\r
+\r
+               /* Needed if string containts anyChar */\r
+               if (firstAnyChar != -1)\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               /* Needed if string contains and anyString in any place\r
+                * other than the last character.\r
+                */\r
+               if (firstAnyString != pattern.length() - 1)\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               return false;\r
+       }\r
+\r
+       /**\r
+        * Pad a string with null characters, in order to make it &gt; and &lt;\r
+        * comparable with SQLChar.\r
+        * \r
+        * @param string        The string to pad\r
+        * @param len           Max number of characters to pad to\r
+        * @return the string padded with 0s up to the given length\r
+        */\r
+       private static String padWithNulls(String string, int len) \r
+       {\r
+               if(string.length() >= len)\r
+                       return string;\r
+\r
+               StringBuffer buf = new StringBuffer(len).append(string);\r
+               buf.setLength(len);\r
+               \r
+               return buf.toString();\r
+       }\r
+}\r