PR: 37169 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@327675 13f79535-47bb-0310-9956-ffa450edef68master
@@ -20,6 +20,7 @@ package org.apache.tools.ant.taskdefs; | |||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.DirectoryScanner; | import org.apache.tools.ant.DirectoryScanner; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.util.StringUtils; | |||||
import org.apache.tools.ant.types.EnumeratedAttribute; | import org.apache.tools.ant.types.EnumeratedAttribute; | ||||
import org.apache.tools.ant.types.FileSet; | import org.apache.tools.ant.types.FileSet; | ||||
@@ -441,7 +442,7 @@ public class SQLExec extends JDBCTask { | |||||
protected void runStatements(Reader reader, PrintStream out) | protected void runStatements(Reader reader, PrintStream out) | ||||
throws SQLException, IOException { | throws SQLException, IOException { | ||||
StringBuffer sql = new StringBuffer(); | StringBuffer sql = new StringBuffer(); | ||||
String line = ""; | |||||
String line; | |||||
BufferedReader in = new BufferedReader(reader); | BufferedReader in = new BufferedReader(reader); | ||||
@@ -481,7 +482,7 @@ public class SQLExec extends JDBCTask { | |||||
} | } | ||||
} | } | ||||
if ((delimiterType.equals(DelimiterType.NORMAL) | if ((delimiterType.equals(DelimiterType.NORMAL) | ||||
&& sql.toString().endsWith(delimiter)) | |||||
&& StringUtils.endsWith(sql, delimiter)) | |||||
|| | || | ||||
(delimiterType.equals(DelimiterType.ROW) | (delimiterType.equals(DelimiterType.ROW) | ||||
&& line.equals(delimiter))) { | && line.equals(delimiter))) { | ||||
@@ -574,8 +575,7 @@ public class SQLExec extends JDBCTask { | |||||
* @throws SQLException on SQL problems. | * @throws SQLException on SQL problems. | ||||
*/ | */ | ||||
protected void printResults(PrintStream out) throws SQLException { | protected void printResults(PrintStream out) throws SQLException { | ||||
ResultSet rs = null; | |||||
rs = statement.getResultSet(); | |||||
ResultSet rs = statement.getResultSet(); | |||||
try { | try { | ||||
printResults(rs, out); | printResults(rs, out); | ||||
} finally { | } finally { | ||||
@@ -98,4 +98,35 @@ public final class StringUtils { | |||||
return sw.toString(); | return sw.toString(); | ||||
} | } | ||||
/** | |||||
* Checks that a string buffer ends up with a given string. It may sound trivial with the existing | |||||
* JDK API but the various implementation among JDKs can make those methods extremely resource intensive | |||||
* and perform poorly due to massive memory allocation and copying. See | |||||
* @param buffer the buffer to perform the check on | |||||
* @param suffix the suffix | |||||
* @return <code>true</code> if the character sequence represented by the | |||||
* argument is a suffix of the character sequence represented by | |||||
* the StringBuffer object; <code>false</code> otherwise. Note that the | |||||
* result will be <code>true</code> if the argument is the | |||||
* empty string. | |||||
*/ | |||||
public static boolean endsWith(StringBuffer buffer, String suffix) { | |||||
if (suffix.length() > buffer.length()) { | |||||
return false; | |||||
} | |||||
// this loop is done on purpose to avoid memory allocation performance problems on various JDKs | |||||
// StringBuffer.lastIndexOf() was introduced in jdk 1.4 and implementation is ok though does allocation/copying | |||||
// StringBuffer.toString().endsWith() does massive memory allocation/copying on JDK 1.5 | |||||
// See http://issues.apache.org/bugzilla/show_bug.cgi?id=37169 | |||||
int endIndex = suffix.length() - 1; | |||||
int bufferIndex = buffer.length() - 1; | |||||
while ( endIndex >= 0 ) { | |||||
if ( buffer.charAt(bufferIndex) != suffix.charAt(endIndex) ) { | |||||
return false; | |||||
} | |||||
bufferIndex--; | |||||
endIndex--; | |||||
} | |||||
return true; | |||||
} | |||||
} | } |
@@ -55,4 +55,51 @@ public class StringUtilsTest extends TestCase { | |||||
assertEquals("bcbcbc", res); | assertEquals("bcbcbc", res); | ||||
} | } | ||||
public void testEndsWithBothEmpty() { | |||||
assertTrue( StringUtils.endsWith( new StringBuffer(), "") ); | |||||
} | |||||
public void testEndsWithEmptyString() { | |||||
assertTrue( StringUtils.endsWith( new StringBuffer("12234545"), "") ); | |||||
} | |||||
public void testEndsWithShorterString() { | |||||
assertTrue( StringUtils.endsWith( new StringBuffer("12345678"), "78")); | |||||
} | |||||
public void testEndsWithSameString() { | |||||
assertTrue( StringUtils.endsWith( new StringBuffer("123"), "123")); | |||||
} | |||||
public void testEndsWithLongerString() { | |||||
assertFalse( StringUtils.endsWith( new StringBuffer("12"), "1245")); | |||||
} | |||||
public void testEndsWithNoMatch() { | |||||
assertFalse( StringUtils.endsWith( new StringBuffer("12345678"), "789")); | |||||
} | |||||
public void testEndsWithEmptyBuffer() { | |||||
assertFalse( StringUtils.endsWith( new StringBuffer(""), "12345667") ); | |||||
} | |||||
public void testEndsWithJDKPerf() { | |||||
StringBuffer buf = getFilledBuffer(1024*300, 'a'); | |||||
for (int i = 0; i < 1000; i++) { | |||||
assertTrue(buf.toString().endsWith("aa")); | |||||
} | |||||
} | |||||
public void testEndsWithPerf() { | |||||
StringBuffer buf = getFilledBuffer(1024*300, 'a'); | |||||
for (int i = 0; i < 1000; i++) { | |||||
assertTrue(StringUtils.endsWith(buf, "aa")); | |||||
} | |||||
} | |||||
private StringBuffer getFilledBuffer(int size, char ch) { | |||||
StringBuffer buf = new StringBuffer(size); | |||||
for (int i = 0; i < size; i++) { buf.append(ch); }; | |||||
return buf; | |||||
} | |||||
} | } |