Skip to content

Commit cb0af75

Browse files
committed
feat: allow SELECT without target expressions for PostgreSQL
Resolves #2784
1 parent 6c5fc6c commit cb0af75

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
@@ -8985,7 +8985,14 @@ PlainSelect PlainSelect() #PlainSelect:
89858985

89868986
[ LOOKAHEAD(2) top = Top() { plainSelect.setTop(top); } ]
89878987

8988-
selectItems=SelectItemsList()
8988+
(
8989+
// PostgreSQL allows SELECT with no target expressions.
8990+
LOOKAHEAD({ Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect))
8991+
&& getToken(1).kind == K_FROM })
8992+
{ selectItems = new ArrayList<SelectItem<?>>(); }
8993+
|
8994+
selectItems=SelectItemsList()
8995+
)
89898996

89908997
[ LOOKAHEAD(<K_INTO>)
89918998
(

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,6 +2398,21 @@ public void testBooleanTestAfterPredicate() throws JSQLParserException {
23982398
assertSqlCanBeParsedAndDeparsed("SELECT * FROM t WHERE a IS TRUE IS FALSE");
23992399
}
24002400

2401+
@Test
2402+
public void testSelectWithoutTargetList_PostgreSql() throws JSQLParserException {
2403+
// PostgreSQL permits SELECT with no target expressions
2404+
Statement stmt = CCJSqlParserUtil.parse(
2405+
"SELECT FROM t", parser -> parser.withDialect(Dialect.POSTGRESQL));
2406+
PlainSelect select = (PlainSelect) ((Select) stmt).getSelectBody();
2407+
assertTrue(select.getSelectItems().isEmpty());
2408+
assertDeparse(select, "SELECT FROM t");
2409+
2410+
// the reported case: empty target list inside a derived table
2411+
assertSqlCanBeParsedAndDeparsed(
2412+
"SELECT count(*) FROM (SELECT FROM (VALUES (1, 'a'), (2, 'b')) AS t(id, label)) AS q",
2413+
false, parser -> parser.withDialect(Dialect.POSTGRESQL));
2414+
}
2415+
24012416
@Test
24022417
public void testIsUnknown() throws JSQLParserException {
24032418
String statement = "SELECT col FROM tbl WHERE col IS UNKNOWN";

0 commit comments

Comments
 (0)