Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/main/java/net/sf/jsqlparser/expression/StringValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,14 @@ public String getNotExcapedValue() {
if (quoteStr != null && quoteStr.startsWith("$")) {
return value;
}
StringBuilder buffer = new StringBuilder(value);
int index = 0;
int deletesNum = 0;
while ((index = value.indexOf("''", index)) != -1) {
buffer.deleteCharAt(index - deletesNum);
index += 2;
deletesNum++;
StringBuilder buffer = new StringBuilder(value.length());
int from = 0;
int index;
while ((index = value.indexOf("''", from)) != -1) {
buffer.append(value, from, index + 1);
from = index + 2;
}
buffer.append(value, from, value.length());
return buffer.toString();
}

Expand Down
24 changes: 24 additions & 0 deletions src/test/java/net/sf/jsqlparser/expression/StringValueTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
package net.sf.jsqlparser.expression;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;

import java.time.Duration;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.test.TestUtils;
Expand Down Expand Up @@ -50,6 +52,28 @@ public void testGetNotExcapedValue() {
assertEquals(expResult, result);
}

@Test
public void testGetNotExcapedValueLargeInputIsLinear() {
// a string literal made of many escaped single quotes used to be unescaped with a
// deleteCharAt() per pair, which is quadratic and lets a modest literal burn CPU
int pairs = 1_000_000;
StringBuilder sb = new StringBuilder(2 * pairs + 2);
sb.append('\'');
for (int i = 0; i < pairs; i++) {
sb.append("''");
}
sb.append('\'');
StringValue instance = new StringValue(sb.toString());

String result = assertTimeoutPreemptively(Duration.ofSeconds(2),
instance::getNotExcapedValue);

assertEquals(pairs, result.length());
for (int i = 0; i < result.length(); i++) {
assertEquals('\'', result.charAt(i));
}
}

@Test
public void testPrefixes() {
checkStringValue("E'test'", "test", "E");
Expand Down
Loading