Skip to content

Commit

Permalink
0002392: SqlScriptReader has a bug where if multiline literals in a
Browse files Browse the repository at this point in the history
statement have a comment at the end of the line, the comment is lost
  • Loading branch information
chenson42 committed Sep 13, 2015
1 parent 8612ded commit 71228b8
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 26 deletions.
64 changes: 49 additions & 15 deletions symmetric-db/src/main/java/org/jumpmind/db/sql/SqlScriptReader.java
Expand Up @@ -131,19 +131,19 @@ protected String prepareForExecute(String toExecute) {

private final String removeComments(String s) {
char[] characters = s.toCharArray();
boolean inLiteral = false;
LiteralInfo literalInfo = null;
boolean inLineComment = false;
boolean inBlockComment = false;
int skipNextCount = 0;

StringBuilder commentsRemoved = new StringBuilder();
char prev = '\0';
int index = 0;
for (char cur : characters) {
if (switchLiteral(prev, cur, inLiteral)) {
inLiteral = !inLiteral;
}

literalInfo = switchLiteral(literalInfo, index, characters);

if (!inLiteral && !inLineComment && !inBlockComment) {
if (literalInfo == null && !inLineComment && !inBlockComment) {
inBlockComment = isBlockCommentStart(prev, cur);
inLineComment = isLineCommentStart(prev, cur);
}
Expand All @@ -155,7 +155,7 @@ private final String removeComments(String s) {
if (inBlockComment && isBlockCommentEnd(prev, cur)) {
inBlockComment = false;
skipNextCount = 2;
}
}

if (!inBlockComment && !inLineComment && skipNextCount == 0) {
commentsRemoved.append(prev);
Expand All @@ -164,6 +164,7 @@ private final String removeComments(String s) {
}

prev = cur;
index++;
}

if (!inBlockComment && !inLineComment && skipNextCount == 0) {
Expand All @@ -189,24 +190,46 @@ private final boolean isBlockCommentEnd(char prev, char cur) {
return (prev == '*' && cur == '/');
}

private final boolean switchLiteral(char prev, char cur, boolean inLiteral) {
return (prev == '\'' && !inLiteral || (inLiteral && cur != '\'' && prev == '\'')) || (prev == '"') || (prev == '`');
private final LiteralInfo switchLiteral(LiteralInfo literalInfo, int currentIndex, char[] statement) {
if (literalInfo == null && currentIndex > 0) {
char prev = statement[currentIndex - 1];
if (prev == '\'' || prev == '"' || prev == '`') {
literalInfo = new LiteralInfo(prev, currentIndex);
}
} else if (literalInfo != null) {
char cur = statement[currentIndex];
char prev = statement[currentIndex - 1];
if (prev == literalInfo.type && cur != literalInfo.type) {
int count = 0;
for (int i = currentIndex - 2; i >= literalInfo.startIndex; i--) {
char check = statement[i];
if (check == literalInfo.type) {
count++;
} else {
break;
}
}
if (count%2==0) {
literalInfo = null;
}
}
}

return literalInfo;
}

private final boolean checkStatementEnds(String s) {
char[] characters = s.toCharArray();
boolean inLiteral = false;
LiteralInfo literalInfo = null;
boolean inLineComment = false;
boolean inBlockComment = false;

char prev = '\0';
int index = 0;
int index = 0;
for (char cur : characters) {
if (switchLiteral(prev, cur, inLiteral)) {
inLiteral = !inLiteral;
}
literalInfo = switchLiteral(literalInfo, index, characters);

if (!inLiteral && !inLineComment && !inBlockComment) {
if (literalInfo == null && !inLineComment && !inBlockComment) {
inBlockComment = isBlockCommentStart(prev, cur);
inLineComment = isLineCommentStart(prev, cur);
}
Expand All @@ -219,7 +242,7 @@ private final boolean checkStatementEnds(String s) {
inBlockComment = false;
}

if (!inLiteral && !inBlockComment && !inLineComment && s.substring(index).startsWith(delimiter)) {
if (literalInfo == null && !inBlockComment && !inLineComment && s.substring(index).startsWith(delimiter)) {
return true;
}

Expand All @@ -229,4 +252,15 @@ private final boolean checkStatementEnds(String s) {
return false;
}

class LiteralInfo {

public LiteralInfo(char type, int startIndex) {
this.type = type;
this.startIndex = startIndex;
}

char type;
int startIndex;
}

}
Expand Up @@ -31,36 +31,58 @@ public class SqlScriptReaderTest {
@Test
public void testReadScript() throws Exception {
SqlScriptReader reader = new SqlScriptReader(new InputStreamReader(getClass().getResourceAsStream("/test-script-1.sql")));
String sql = reader.readSqlStatement();
assertEquals("select * from \n TEST where\n \n id = 'someid'", sql);

String nextStatement = reader.readSqlStatement();
assertEquals("select * from \n TEST where\n \n id = 'someid'", nextStatement);

assertEquals("select * from test", reader.readSqlStatement());
assertEquals("insert into test (one, two, three) values('1','1','2')", reader.readSqlStatement());
for (int i = 0; i < 4; i++) {
assertEquals("delete from test where one='1'", reader.readSqlStatement());
}
assertEquals("update sym_node set sync_url='http://localhost:8080/test' where node_id='test'", reader.readSqlStatement());
assertEquals("update something set oops=';' where whoops='test'", reader.readSqlStatement());
assertEquals("update test set one = '''', two='\\\\##--''' where one is null", reader.readSqlStatement());

nextStatement = reader.readSqlStatement();
assertEquals("update sym_node set sync_url='http://localhost:8080/test' where node_id='test'", nextStatement);

nextStatement = reader.readSqlStatement();
assertEquals("update something set oops=';' where whoops='test'", nextStatement);

nextStatement = reader.readSqlStatement();
assertEquals("update test set one = '''', two='\\\\##--''' where one is null", nextStatement);

assertEquals("update test\n set one = '1', two = '2'\n where one = 'one'", reader.readSqlStatement());
assertEquals("create table \"TE--ST\" (\"ID##2\" VARCHAR(100))", reader.readSqlStatement());
sql = reader.readSqlStatement();

nextStatement = reader.readSqlStatement();
assertEquals("insert into test (col) values('import org.x.Test;\n" +
"import com.y.Testy;\n" +
"\n" +
"class A {\n" +
" int x, y = 0;\n" +
"}\n" +
"')",sql);
"')",nextStatement);

assertEquals("insert into test (col) values('<!--\n" +
"<test></test>\n" +
"-->')", reader.readSqlStatement());

assertEquals("insert into test (col1,col2) values('<!--', \n" +
"'<test></test>')", reader.readSqlStatement());

assertEquals("select col1 /* test */, col2 /* col2 */ from rubixcube", reader.readSqlStatement());
reader.setStripOutBlockComments(true);
String statement = reader.readSqlStatement();
assertEquals("select col1 , col2 from rubixcube", statement);

reader.setStripOutBlockComments(true);
nextStatement = reader.readSqlStatement();
assertEquals("select col1 , col2 from rubixcube", nextStatement);

nextStatement = reader.readSqlStatement();

assertEquals("insert into test (col1, col2) ('test', '\n" +
"''test'';\n" +
"')", nextStatement);

assertNull(reader.readSqlStatement());

reader.close();
}
}
6 changes: 5 additions & 1 deletion symmetric-db/src/test/resources/test-script-1.sql
Expand Up @@ -53,4 +53,8 @@ insert into test (col) values('<!--
insert into test (col1,col2) values('<!--', -- test
'<test></test>');
select col1 /* test */, col2 /* col2 */ from rubixcube;
select col1 /* test */, col2 /* col2 */ from rubixcube;
select col1 /* test */, col2 /* col2 */ from rubixcube;

insert into test (col1, col2) ('test', '
''test'';
');

0 comments on commit 71228b8

Please sign in to comment.