db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r413123 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/types/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Fri, 09 Jun 2006 18:38:45 GMT
Author: kahatlen
Date: Fri Jun  9 11:38:44 2006
New Revision: 413123

URL: http://svn.apache.org/viewvc?rev=413123&view=rev
Log:
DERBY-1386: Wrong results with query using LIKE and ESCAPE clause that
includes "%", "\", and "_"

Queries using LIKE/ESCAPE could return wrong results if the first
wildcard character was preceded by an even number of escape
characters. This patch fixes the issue by changing the way
Like.lessThanString() parses the pattern string.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/Like.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dynamicLikeOptimization.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/dynamicLikeOptimization.sql

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/Like.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/Like.java?rev=413123&r1=413122&r2=413123&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/Like.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/Like.java Fri Jun  9 11:38:44
2006
@@ -852,58 +852,6 @@
 		return new String(result, 0, r);
 	}
 
-	/**
-	 * Return the substring from the pattern for the < clause.
-	 * (NOTE: This may be null in the degenerate case where the
-	 * last char before the first wild card can't be incremented.)
-	 *
-	 *		Optimized for ESCAPE
-	 *
-	 * This function uses the greaterThanString, and bumps its last
-	 * character by one.   This string has no escape characters, they
-	 * were stripped out, and ends just before any real pattern chars or
-	 * at the end of the pattern literal.    See LikeEscapeOp*Node.preprocess.
-	 *
-	 * @param pattern	The right side of the LIKE
-	 * @param maxWidth	Maximum length of column, for null padding
-	 *
-	 * @return	The String for the < clause
-	 * @exception StandardException thrown if data invalid
-	 */
-	public static String lessThanString(String pattern, int maxWidth)
-		throws StandardException
-	{
-		//int		firstAnyChar = pattern.indexOf(anyChar);
-		//int		firstAnyString = pattern.indexOf(anyString);
-		int		lastUsableChar;
-		int		patternLen;
-		char	oldLastChar;
-		char	newLastChar;
-		char[]	charArray;
-
-		if ((patternLen = pattern.length()) == 0)
-		{
-			// pattern is ""
-			return null;
-		}
-		
-		lastUsableChar = patternLen -1;
-		oldLastChar = pattern.charAt(lastUsableChar);
-		newLastChar = oldLastChar;
-		newLastChar++;
-
-		// Check for degenerate roll over
-		if (newLastChar < oldLastChar)
-		{
-			return null;
-		}
-
-		charArray = pattern.substring(0, lastUsableChar + 1).toCharArray();
-		charArray[lastUsableChar] = newLastChar;
-
-		return padWithNulls(new String(charArray), maxWidth);
-	}
-
 	public static String lessThanStringFromParameter(String pattern, int maxWidth)
 		throws StandardException 
 	{
@@ -922,11 +870,7 @@
 
 	/**
 	 * Return the substring from the pattern for the < clause.
-	 * (NOTE: This may be null in the degenerate case where the
-	 * last char before the first wild card can't be incremented.)
-	 *
-	 * 		This is unoptimized for ESCAPE.
-	 *
+	 * (NOTE: This may be null if the pattern is an empty string.)
 	 *
 	 * @param pattern	The right side of the LIKE
 	 * @param escape	The escape clause
@@ -939,13 +883,11 @@
 		throws StandardException
 	{
 		int		lastUsableChar;
-		int		patternLen;
 		char	oldLastChar;
 		char	newLastChar;
-		char[]	charArray;
-		char escChar = 'a';
+		final int escChar;
 
-		if ((patternLen = pattern.length()) == 0)
+		if (pattern.length() == 0)
 		{
 			// pattern is ""
 			return null;
@@ -955,6 +897,11 @@
 		{
 			escChar = escape.charAt(0);
 		}
+		else {
+			// Set escape character to a value outside the char range,
+			// so that comparison with a char always evaluates to false.
+			escChar = -1;
+		}
 
 		/* Find the last non-wildcard character in the pattern
 		 * and increment it.  In the most common case,
@@ -963,64 +910,37 @@
 		 *
 		 *	pattern			return
 		 *	-------			------
-		 *	""				SUPER_STRING (match against super string)
+		 *	""				null
 		 *	"%..."			SUPER_STRING (match against super string)
 		 *	"_..."			SUPER_STRING (match against super string)
 		 *	"asdf%"			"asdg"
 		 */
 
-		int		firstAnyChar = pattern.indexOf(anyChar);
-		int		firstAnyString = pattern.indexOf(anyString);
+		StringBuffer upperLimit = new StringBuffer(maxWidth);
 
-
-		if (escape != null)
-		{
-			while (firstAnyChar > 0 && pattern.charAt(firstAnyChar-1) == escChar)
-				firstAnyChar = pattern.indexOf(anyChar, firstAnyChar+1);
-			while (firstAnyString > 0 && pattern.charAt(firstAnyString-1) == escChar)
-				firstAnyString = pattern.indexOf(anyString, firstAnyString+1);
-		}
-
-		if (firstAnyChar == -1)
-		{
-			if (firstAnyString == -1)
-			{
-				lastUsableChar = pattern.length() -1;
-			}
-			else if (firstAnyString == 0)
-			{
-				// pattern is "%"
-				return SUPER_STRING;
-			}
-			else
-			{
-				lastUsableChar = firstAnyString - 1;
-			}
-		}
-		else if (firstAnyString == -1)
-		{
-			if (firstAnyChar == 0)
-			{
-				// pattern is "_"
-				return SUPER_STRING;
+		// Extract the string leading up to the first wildcard.
+		for (int i = 0; i < pattern.length(); i++) {
+			char c = pattern.charAt(i);
+			if (c == escChar) {
+				if (++i >= pattern.length()) {
+					throw StandardException.newException(
+							SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
+				}
+				c = pattern.charAt(i);
+			} else if (c == anyChar || c == anyString) {
+				break;
 			}
-			lastUsableChar = firstAnyChar - 1;
+			upperLimit.append(c);
 		}
-		else
-		{
-			// both _ and % present
-			lastUsableChar = ((firstAnyChar > firstAnyString) ? 
-										firstAnyString :
-										firstAnyChar) - 1;
-
-			if (lastUsableChar == -1)
-			{
-				// pattern starts with a wildcard
-				return SUPER_STRING;
-			}
+
+		// Pattern starts with wildcard.
+		if (upperLimit.length() == 0) {
+			return SUPER_STRING;
 		}
 
-		oldLastChar = pattern.charAt(lastUsableChar);
+		// Increment the last non-wildcard character.
+		lastUsableChar = upperLimit.length() - 1;
+		oldLastChar = upperLimit.charAt(lastUsableChar);
 		newLastChar = oldLastChar;
 		newLastChar++;
 
@@ -1030,37 +950,14 @@
 			return SUPER_STRING;
 		}
 
-		if (escape == null)
-		{
-			charArray = pattern.substring(0, lastUsableChar + 1).toCharArray();
-			charArray[lastUsableChar] = newLastChar;
+		upperLimit.setCharAt(lastUsableChar, newLastChar);
 
-			return padWithNulls(new String(charArray), maxWidth);
+		// Pad the string with nulls.
+		if (upperLimit.length() < maxWidth) {
+			upperLimit.setLength(maxWidth);
 		}
-		char[] patternChars = new char[patternLen];
-		char[] result = new char[patternLen];
-		pattern.getChars(0, patternLen, patternChars, 0) ;
 
-		int r = 0;
-		for (int p = 0; p < lastUsableChar; p++)
-		{
-		    if (patternChars[p] == escChar)
-			{
-				p++;		// don't copy the escape char
-
-				// run out: eg.  Escape char last char?
-				if (p >= patternLen-1)
-					throw StandardException.newException(
-							SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
-				result[r++] = patternChars[p];
-				continue;
-			}
-
-			result[r++] = patternChars[p];
-		}
-		result[r++] = newLastChar;
-		String gt = new String(result, 0, r);
-		return padWithNulls(gt, maxWidth);
+		return upperLimit.toString();
 	}
 	
 	/**

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dynamicLikeOptimization.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dynamicLikeOptimization.out?rev=413123&r1=413122&r2=413123&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dynamicLikeOptimization.out
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dynamicLikeOptimization.out
Fri Jun  9 11:38:44 2006
@@ -519,6 +519,41 @@
 asdf      
 asdg      
 asdp     
+ij> -- escaped escape character preceding first wildcard (DERBY-1386)
+insert into test values ('abc#def', 'abc#def', 'abc#def');
+1 row inserted/updated/deleted
+ij> insert into test values ('abc\def', 'abc\def', 'abc\def');
+1 row inserted/updated/deleted
+ij> select id from test where c10 like 'abc##%' escape '#';
+ID        
+----------
+abc#def   
+ij> select id from test where vc10 like 'abc##%' escape '#';
+ID        
+----------
+abc#def   
+ij> select id from test where c10 like 'abc\\%' escape '\';
+ID        
+----------
+abc\def   
+ij> select id from test where vc10 like 'abc\\%' escape '\';
+ID        
+----------
+abc\def   
+ij> select id from test where c10 like 'abc##_ef' escape '#';
+ID        
+----------
+ij> select id from test where vc10 like 'abc##_ef' escape '#';
+ID        
+----------
+abc#def   
+ij> select id from test where c10 like 'abc\\_ef' escape '\';
+ID        
+----------
+ij> select id from test where vc10 like 'abc\\_ef' escape '\';
+ID        
+----------
+abc\def   
 ij> -- clean up
 drop table test;
 0 rows inserted/updated/deleted

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/dynamicLikeOptimization.sql
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/dynamicLikeOptimization.sql?rev=413123&r1=413122&r2=413123&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/dynamicLikeOptimization.sql
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/dynamicLikeOptimization.sql
Fri Jun  9 11:38:44 2006
@@ -176,6 +176,18 @@
 execute p1 using 'values ''asd%'' ';
 select c10 from test where c10 like 'asd%';
 
+-- escaped escape character preceding first wildcard (DERBY-1386)
+insert into test values ('abc#def', 'abc#def', 'abc#def');
+insert into test values ('abc\def', 'abc\def', 'abc\def');
+select id from test where c10 like 'abc##%' escape '#';
+select id from test where vc10 like 'abc##%' escape '#';
+select id from test where c10 like 'abc\\%' escape '\';
+select id from test where vc10 like 'abc\\%' escape '\';
+select id from test where c10 like 'abc##_ef' escape '#';
+select id from test where vc10 like 'abc##_ef' escape '#';
+select id from test where c10 like 'abc\\_ef' escape '\';
+select id from test where vc10 like 'abc\\_ef' escape '\';
+
 -- clean up
 drop table test;
 drop table likeable;



Mime
View raw message