Skip to content

Commit 513fe95

Browse files
committed
feat: allow SELECT without target expressions for PostgreSQL
Resolves #2784
1 parent f6ac257 commit 513fe95

4 files changed

Lines changed: 35 additions & 1 deletion

File tree

‎src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,10 +629,16 @@ public StringBuilder appendSelectBodyTo(StringBuilder builder) {
629629

630630
private void appendSelectClauseTo(StringBuilder builder) {
631631
builder.append("SELECT ");
632+
int afterSelect = builder.length();
632633
appendSelectHintsTo(builder);
633634
appendSelectQualifiersTo(builder);
634635
appendMySqlSelectModifiersTo(builder);
635636
builder.append(getStringList(selectItems));
637+
// PostgreSQL permits SELECT with no target expressions: keep "SELECT
638+
// FROM" instead of doubling the space.
639+
if (builder.length() == afterSelect) {
640+
builder.deleteCharAt(afterSelect - 1);
641+
}
636642
}
637643

638644
private void appendSelectHintsTo(StringBuilder builder) {

‎src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,13 @@ private <S> void deparseSelectClause(PlainSelect plainSelect, S context) {
379379

380380
plainSelect.appendMySqlSelectModifiersTo(builder);
381381

382+
int beforeItems = builder.length();
382383
deparseSelectItemsClause(plainSelect.getSelectItems());
384+
// PostgreSQL permits SELECT with no target expressions: keep "SELECT
385+
// FROM" instead of doubling the space.
386+
if (builder.length() == beforeItems && builder.charAt(beforeItems - 1) == ' ') {
387+
builder.deleteCharAt(beforeItems - 1);
388+
}
383389

384390
if (plainSelect.getIntoTables() != null) {
385391
builder.append(" INTO ");

‎src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8482,7 +8482,14 @@ PlainSelect PlainSelect() #PlainSelect:
84828482

84838483
[ LOOKAHEAD(2) top = Top() { plainSelect.setTop(top); } ]
84848484

8485-
selectItems=SelectItemsList()
8485+
(
8486+
// PostgreSQL allows SELECT with no target expressions.
8487+
LOOKAHEAD({ Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect))
8488+
&& getToken(1).kind == K_FROM })
8489+
{ selectItems = new ArrayList<SelectItem<?>>(); }
8490+
|
8491+
selectItems=SelectItemsList()
8492+
)
84868493

84878494
[ LOOKAHEAD(<K_INTO>)
84888495
(

‎src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,6 +2388,21 @@ public void testIsNotFalse() throws JSQLParserException {
23882388
assertSqlCanBeParsedAndDeparsed(statement);
23892389
}
23902390

2391+
@Test
2392+
public void testSelectWithoutTargetList_PostgreSql() throws JSQLParserException {
2393+
// PostgreSQL permits SELECT with no target expressions
2394+
Statement stmt = CCJSqlParserUtil.parse(
2395+
"SELECT FROM t", parser -> parser.withDialect(Dialect.POSTGRESQL));
2396+
PlainSelect select = (PlainSelect) ((Select) stmt).getSelectBody();
2397+
assertTrue(select.getSelectItems().isEmpty());
2398+
assertDeparse(select, "SELECT FROM t");
2399+
2400+
// the reported case: empty target list inside a derived table
2401+
assertSqlCanBeParsedAndDeparsed(
2402+
"SELECT count(*) FROM (SELECT FROM (VALUES (1, 'a'), (2, 'b')) AS t(id, label)) AS q",
2403+
false, parser -> parser.withDialect(Dialect.POSTGRESQL));
2404+
}
2405+
23912406
@Test
23922407
public void testIsUnknown() throws JSQLParserException {
23932408
String statement = "SELECT col FROM tbl WHERE col IS UNKNOWN";

0 commit comments

Comments
 (0)