Skip to content

Commit

Permalink
fix: backslash is not a valid quote escape (#317)
Browse files Browse the repository at this point in the history
The SimpleParser would accept backslash+quote as a valid escape mechanism
for a quote inside a quoted string. This is not correct for PostgreSQL,
and instead should be two equal quotes directly following each other.
  • Loading branch information
olavloite committed Aug 15, 2022
1 parent 819a653 commit dc32af4
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,12 @@ String parseExpressionUntilKeyword(ImmutableList<String> keywords) {
int parens = 0;
while (pos < sql.length()) {
if (quoted) {
if (sql.charAt(pos) == startQuote && sql.charAt(pos - 1) != '\\') {
quoted = false;
if (sql.charAt(pos) == startQuote) {
if (pos == (sql.length() - 1) || sql.charAt(pos + 1) != startQuote) {
quoted = false;
} else {
pos++;
}
}
} else {
if (sql.charAt(pos) == '\'' || sql.charAt(pos) == '"') {
Expand Down Expand Up @@ -257,19 +261,28 @@ private boolean internalEat(
boolean skipWhitespaceBefore,
boolean requireWhitespaceAfter,
boolean updatePos) {
int originalPos = pos;
if (skipWhitespaceBefore) {
skipWhitespaces();
}
if (pos + keyword.length() > sql.length()) {
if (!updatePos) {
pos = originalPos;
}
return false;
}
if (sql.substring(pos, pos + keyword.length()).equalsIgnoreCase(keyword)
&& (!requireWhitespaceAfter || isValidEndOfKeyword(pos + keyword.length()))) {
if (updatePos) {
pos = pos + keyword.length();
} else {
pos = originalPos;
}
return true;
}
if (!updatePos) {
pos = originalPos;
}
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ public void testTransformUpdateToSelectParams() {
"select $1, $2, $3 from (select col1=$1, col2=$2 from foo where id=$3) p",
transformUpdate("update foo set col1=$1, col2=$2 where id=$3").getSql());
assertEquals(
"select $1, $2, $3 from (select col1=col2 + $1 , "
"select $1, $2, $3 from (select col1=col2 + $1, "
+ "col2=coalesce($1, $2, $3, to_char(current_timestamp())), "
+ "col3 = 15 "
+ "from foo where id=$3 and value>100) p",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.junit.Assert.assertTrue;

import com.google.cloud.spanner.pgadapter.statements.SimpleParser.TableOrIndexName;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
Expand Down Expand Up @@ -57,6 +58,7 @@ public void testEatKeyword() {
assertTrue(new SimpleParser("select\"id\"from\"foo\"").eatKeyword("select"));
assertTrue(new SimpleParser("select/*comment*/id from foo").eatKeyword("select"));
assertFalse(new SimpleParser("select$$foo$$").eatKeyword("select"));
assertFalse(new SimpleParser("'select").eatKeyword("select"));
}

@Test
Expand Down Expand Up @@ -189,9 +191,9 @@ public void testParseExpression() {
assertEquals(
"(foo('bar\", test'))", new SimpleParser(" (foo('bar\", test')),bar").parseExpression());
assertEquals(
"(foo('bar\\', test'))", new SimpleParser(" (foo('bar\\', test')),bar").parseExpression());
"(foo('bar'', test'))", new SimpleParser(" (foo('bar'', test')),bar").parseExpression());
assertEquals("''", new SimpleParser("''").parseExpression());
assertEquals("'\\''", new SimpleParser("'\\''").parseExpression());
assertEquals("''''", new SimpleParser("''''").parseExpression());
assertEquals("'\"'", new SimpleParser("'\"'").parseExpression());

assertNull(new SimpleParser("\"foo").parseExpression());
Expand Down Expand Up @@ -256,11 +258,10 @@ public void testParseExpressionList() {
Arrays.asList("(foo('bar\", test'))", "bar"),
new SimpleParser(" (foo('bar\", test')),bar").parseExpressionList());
assertEquals(
Arrays.asList("(foo('bar\\', test'))", "bar"),
new SimpleParser(" (foo('bar\\', test')),bar").parseExpressionList());
Arrays.asList("(foo('bar'', test'))", "bar"),
new SimpleParser(" (foo('bar'', test')),bar").parseExpressionList());
assertEquals(Collections.singletonList("''"), new SimpleParser("''").parseExpressionList());
assertEquals(
Collections.singletonList("'\\''"), new SimpleParser("'\\''").parseExpressionList());
assertEquals(Collections.singletonList("''''"), new SimpleParser("''''").parseExpressionList());
assertEquals(Collections.singletonList("'\"'"), new SimpleParser("'\"'").parseExpressionList());

assertNull(new SimpleParser("\"foo").parseExpressionList());
Expand All @@ -271,4 +272,40 @@ public void testParseExpressionList() {
assertNull(new SimpleParser("foo((bar, test) bar").parseExpressionList());
assertEquals(Collections.singletonList("foo"), new SimpleParser("foo)(").parseExpressionList());
}

@Test
public void testParseExpressionUntil() {
assertEquals(
"insert into foo values ('select')",
new SimpleParser("insert into foo values ('select')")
.parseExpressionUntilKeyword(ImmutableList.of("select")));
assertEquals(
"insert into foo",
new SimpleParser("insert into foo select * from bar")
.parseExpressionUntilKeyword(ImmutableList.of("select")));
assertEquals(
"insert into foo values ('''select''')",
new SimpleParser("insert into foo values ('''select''')")
.parseExpressionUntilKeyword(ImmutableList.of("select")));
assertEquals(
"insert into foo (\"''\")",
new SimpleParser("insert into foo (\"''\") select * from bar")
.parseExpressionUntilKeyword(ImmutableList.of("select")));
assertEquals(
"insert into foo values ('''select''')",
new SimpleParser("insert into foo values ('''select''') select 1")
.parseExpressionUntilKeyword(ImmutableList.of("select")));
assertEquals(
"select \"insert\" from bar",
new SimpleParser("select \"insert\" from bar")
.parseExpressionUntilKeyword(ImmutableList.of("insert")));
assertEquals(
"select \"\"\"insert\"\"\" from bar",
new SimpleParser("select \"\"\"insert\"\"\" from bar")
.parseExpressionUntilKeyword(ImmutableList.of("insert")));
assertEquals(
"insert into foo (\"\"\"\")",
new SimpleParser("insert into foo (\"\"\"\") select * from bar")
.parseExpressionUntilKeyword(ImmutableList.of("select")));
}
}

0 comments on commit dc32af4

Please sign in to comment.