Skip to content

Commit

Permalink
feat: T-SQL FOR ... clause
Browse files Browse the repository at this point in the history
  • Loading branch information
manticore-projects committed Jun 2, 2023
1 parent 6d2b421 commit 8027dbf
Show file tree
Hide file tree
Showing 9 changed files with 296 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
}

StringBuilder appendTo(StringBuilder builder) {
public StringBuilder appendTo(StringBuilder builder) {
builder.append("Trim(");

if (trimSpecification != null) {
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,15 @@ public void setASTNode(SimpleNode node) {
this.node = node;
}

public StringBuilder appendTo(StringBuilder builder) {
SimpleNode simpleNode = getASTNode();
Token token = simpleNode.jjtGetFirstToken();
Token lastToken = simpleNode.jjtGetLastToken();
while (token.next != null && token.absoluteEnd <= lastToken.absoluteEnd) {
builder.append(" ").append(token.image);
token = token.next;
}
return builder;
}

}
29 changes: 29 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/select/ForClause.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package net.sf.jsqlparser.statement.select;

import net.sf.jsqlparser.parser.ASTNodeAccessImpl;

public class ForClause extends ASTNodeAccessImpl {
public enum ForOption {
BROWSE, XML, JSON;

public static ForOption from(String option) {
return Enum.valueOf(ForOption.class, option.toUpperCase());
}
}

private ForOption forOption;

public ForOption getForOption() {
return forOption;
}

public ForClause setForOption(String forOption) {
this.forOption = ForOption.from(forOption);
return this;
}

@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
}
}
16 changes: 16 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/select/Select.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public abstract class Select extends ASTNodeAccessImpl implements Statement, Exp
Fetch fetch;
WithIsolation isolation;
boolean oracleSiblings = false;

ForClause forClause = null;

List<OrderByElement> orderByElements;

public static String orderByToString(List<OrderByElement> orderByElements) {
Expand Down Expand Up @@ -154,6 +157,15 @@ public Select withOracleSiblings(boolean oracleSiblings) {
return this;
}

public ForClause getForClause() {
return forClause;
}

public Select setForClause(ForClause forClause) {
this.forClause = forClause;
return this;
}

public List<OrderByElement> getOrderByElements() {
return orderByElements;
}
Expand Down Expand Up @@ -261,6 +273,10 @@ public StringBuilder appendTo(StringBuilder builder) {

appendSelectBodyTo(builder);

if (forClause != null) {
forClause.appendTo(builder);
}

builder.append(orderByToString(oracleSiblings, orderByElements));

if (limitBy != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -820,12 +820,12 @@ public void visit(IntervalExpression intervalExpression) {
if (intervalExpression.isUsingIntervalKeyword()) {
buffer.append("INTERVAL ");
}
if (intervalExpression.getExpression()!=null) {
if (intervalExpression.getExpression() != null) {
intervalExpression.getExpression().accept(this);
} else {
buffer.append(intervalExpression.getParameter());
}
if (intervalExpression.getIntervalType()!=null) {
if (intervalExpression.getIntervalType() != null) {
buffer.append(" ").append(intervalExpression.getIntervalType());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ public void visit(PlainSelect plainSelect) {
buffer.append(" SKIP LOCKED");
}
}
if (plainSelect.getForClause() != null) {
plainSelect.getForClause().appendTo(buffer);
}

if (plainSelect.getOrderByElements() != null) {
new OrderByDeParser(expressionVisitor, buffer).deParse(plainSelect.isOracleSiblings(),
plainSelect.getOrderByElements());
Expand Down
181 changes: 138 additions & 43 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package net.sf.jsqlparser.statement.select;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.test.TestUtils;
import org.junit.jupiter.api.Test;

class ForClauseTest {

@Test
void testForBrowse() throws JSQLParserException {
String sqlStr = "SELECT * FROM table FOR BROWSE";
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

@Test
void testForXMLPath() throws JSQLParserException {
String sqlStr =
"SELECT * " +
" FROM table " +
" FOR XML PATH('something'), ROOT('trkseg'), TYPE, BINARY BASE64, ELEMENTS ABSENT ";
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

@Test
void testForXMLRaw() throws JSQLParserException {
String sqlStr =
"SELECT * " +
" FROM table " +
" FOR XML RAW('something'), ROOT('trkseg'), TYPE, BINARY BASE64, XMLDATA ";
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

@Test
void testForXMLAuto() throws JSQLParserException {
String sqlStr =
"SELECT * " +
" FROM table " +
" FOR XML AUTO, ROOT('trkseg'), TYPE, BINARY BASE64, XMLDATA ";
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

@Test
void testForXMLExplicit() throws JSQLParserException {
String sqlStr =
"SELECT * " +
" FROM table " +
" FOR XML EXPLICIT, ROOT('trkseg'), TYPE, BINARY BASE64, XMLDATA ";
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

@Test
void testForXML() throws JSQLParserException {
String sqlStr =
"SELECT * " +
" FROM table " +
" FOR XML EXPLICIT, ROOT('trkseg'), TYPE, BINARY BASE64, XMLDATA " +
"UNION ALL " +
"SELECT * " +
" FROM table " +
" FOR XML EXPLICIT, ROOT('trkseg'), TYPE, BINARY BASE64, XMLDATA " +
"UNION ALL " +
"SELECT * " +
" FROM table " +
" FOR XML AUTO, ROOT('trkseg'), TYPE, BINARY BASE64, XMLDATA " +
"UNION ALL " +
"SELECT * " +
" FROM table " +
" FOR XML RAW('something'), ROOT('trkseg'), TYPE, BINARY BASE64, XMLDATA ";
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

@Test
void testForJSON() throws JSQLParserException {
String sqlStr =
"SELECT * " +
" FROM table " +
" FOR JSON AUTO, ROOT('trkseg'), WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES "
+
"UNION ALL " +
"SELECT * " +
" FROM table " +
" FOR JSON PATH, ROOT('trkseg'), INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER ";
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

@Test
void testIssue1800() throws JSQLParserException {
String sqlStr =
"SELECT (SELECT '1.0' AS '@Version', (SELECT 'Test' AS 'name', (SELECT (SELECT DISTINCT 51.64315 AS '@lat', 14.31709 AS '@lon' FOR XML PATH('trkpt'), TYPE) FOR XML PATH(''), ROOT('trkseg'), TYPE) FOR XML PATH('trk'), TYPE) FOR XML PATH('gpx'), TYPE) FOR XML PATH('')";
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4213,7 +4213,8 @@ public void testSqlContainIsNullFunctionShouldBeParsed3() throws JSQLParserExcep
@Test
public void testForXmlPath() throws JSQLParserException {
assertSqlCanBeParsedAndDeparsed(
"SELECT '|' + person_name FROM person JOIN person_group ON person.person_id = person_group.person_id WHERE person_group.group_id = 1 FOR XML PATH('')");
"SELECT '|' + person_name FROM person JOIN person_group ON person.person_id = person_group.person_id WHERE person_group.group_id = 1 FOR XML PATH('')",
true);
}

// @Test
Expand Down

0 comments on commit 8027dbf

Please sign in to comment.