Skip to content
Merged
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
23 changes: 23 additions & 0 deletions src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
*/
package net.sf.jsqlparser.parser;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

Expand All @@ -26,6 +29,26 @@ public void setASTNode(Node node) {
this.node = node;
}

/**
* The comments preceding this node's first token, in source order, with the original token
* images. Line comments do not include their line terminator; callers must add a line break
* when prepending them to SQL. Empty for nodes built programmatically, which carry no AST.
*/
public List<String> getLeadingComments() {
Node node = getASTNode();
if (node == null) {
return new ArrayList<>();
}
List<String> comments = new ArrayList<>();
for (Token specialToken =
node.jjtGetFirstToken().specialToken; specialToken != null; specialToken =
specialToken.specialToken) {
comments.add(specialToken.image);
}
Collections.reverse(comments);
return comments;
}

public StringBuilder appendTo(StringBuilder builder) {
// don't add spaces around the following punctuation
final Set<String> punctuation = new TreeSet<>(Set.of(".", "[", "]"));
Expand Down
80 changes: 80 additions & 0 deletions src/test/java/net/sf/jsqlparser/parser/LeadingCommentsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2019 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.parser;

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

import java.util.List;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.statement.Statements;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class LeadingCommentsTest {

@Test
public void blockCommentsBeforeStatementInSourceOrder() throws JSQLParserException {
Select select = (Select) CCJSqlParserUtil
.parse("/* keep orderby */ /*+ FULL(t) */ SELECT * FROM mytable");
assertEquals(List.of("/* keep orderby */", "/*+ FULL(t) */"), select.getLeadingComments());
}

@ParameterizedTest
@ValueSource(strings = {"\n", "\r\n", "\r"})
public void lineCommentsExcludeLineTerminators(String lineTerminator)
throws JSQLParserException {
Select select =
(Select) CCJSqlParserUtil.parse("-- paging hint" + lineTerminator + "SELECT 1");
assertEquals(List.of("-- paging hint"), select.getLeadingComments());
}

@Test
public void mixedCommentsRetainExactImagesAndSourceOrder() throws JSQLParserException {
Select select = (Select) CCJSqlParserUtil
.parse("/* a */ -- b\r\n// c\r/* d */ SELECT 1");
assertEquals(List.of("/* a */", "-- b", "// c", "/* d */"), select.getLeadingComments());
}

@Test
public void commentInsideStatementIsNotLeading() throws JSQLParserException {
Select select = (Select) CCJSqlParserUtil.parse("SELECT /* mid comment */ 1");
assertEquals(List.of(), select.getLeadingComments());
}

@Test
public void statementWithoutComments() throws JSQLParserException {
Select select = (Select) CCJSqlParserUtil.parse("SELECT * FROM mytable");
assertEquals(List.of(), select.getLeadingComments());
}

@Test
public void programmaticStatementHasNoLeadingComments() {
assertEquals(List.of(), new PlainSelect().getLeadingComments());
}

@Test
public void toStringDropsLeadingCommentsAsBefore() throws JSQLParserException {
Select select = (Select) CCJSqlParserUtil
.parse("/* keep orderby */ SELECT * FROM mytable");
assertFalse(select.toString().contains("/*"));
}

@Test
public void commentsSplitPerStatement() throws JSQLParserException {
Statements statements = CCJSqlParserUtil
.parseStatements("/* first */ SELECT 1; /* second */ SELECT 2");
assertEquals(List.of("/* first */"), ((Select) statements.get(0)).getLeadingComments());
assertEquals(List.of("/* second */"), ((Select) statements.get(1)).getLeadingComments());
}
}
12 changes: 12 additions & 0 deletions src/test/java/net/sf/jsqlparser/statement/SerializationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Stream;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.SpannerInterleaveIn;
Expand All @@ -34,6 +35,17 @@
import org.junit.jupiter.params.provider.ValueSource;

public class SerializationTest {
@Test
void serializeSelectWithLeadingComments() throws Exception {
PlainSelect original = (PlainSelect) CCJSqlParserUtil
.parse("/* keep orderby */ SELECT id FROM mytable");
Assertions.assertEquals(List.of("/* keep orderby */"), original.getLeadingComments());
PlainSelect copy = roundTrip(original);
Assertions.assertEquals("SELECT id FROM mytable", copy.toString());
Assertions.assertNull(copy.getASTNode());
Assertions.assertEquals(List.of(), copy.getLeadingComments());
}

@Test
void serializeWithItem() throws JSQLParserException, IOException, ClassNotFoundException {
String sqlStr =
Expand Down
Loading