From 980d24a6c28368dc58623ddac93d531630d92fd7 Mon Sep 17 00:00:00 2001 From: princejain756 Date: Wed, 21 Oct 2026 16:14:41 +0530 Subject: [PATCH] fix: reject DELETE statements missing a target table DELETE, DELETE FROM, DELETE FROM WHERE ... and DELETE FROM USING ... all parsed successfully into a Delete with a null table, and toString() then printed the literal text "null" (DELETE FROM null WHERE 1 = 1). The grammar's bare-FROM alternative never required a table to follow. The production now validates that a target table was supplied in one of the three supported positions (before FROM, after FROM, or via the table list) through a requireDeleteSyntax() helper, matching the existing requireAccessSyntax()/requireReplicationSyntax() pattern. --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 6 ++++++ .../sf/jsqlparser/statement/delete/DeleteTest.java | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index f49b3ddbae..337fccabc7 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2013,6 +2013,10 @@ public class CCJSqlParser extends AbstractJSqlParser { if (!valid) { throw new ParseException(message); } } + private static void requireDeleteSyntax(boolean valid, String message) throws ParseException { + if (!valid) { throw new ParseException(message); } + } + private static > E replicationEnum(Class type, String value) throws ParseException { try { return Enum.valueOf(type, MultiPartName.unquote(value).toUpperCase(Locale.ROOT)); } catch (IllegalArgumentException exception) { throw new ParseException("Unknown " + type.getSimpleName() + ": " + value); } @@ -7193,6 +7197,8 @@ Delete Delete(): if (joins != null && joins.size() > 0) { delete.setJoins(joins); } + requireDeleteSyntax(table != null || !tables.isEmpty(), + "DELETE requires a target table"); return delete.withWithItemsList(with) .withTables(tables) .withTable(table) diff --git a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java index 2b7bab5e96..f90eeea8e8 100644 --- a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java @@ -74,6 +74,20 @@ public void testDeleteDoesNotAllowLimitOffset() { () -> parserManager.parse(new StringReader(statement))); } + @Test + public void testDeleteRequiresTargetTable() { + // a missing target must not parse into a Delete whose toString() + // prints a literal "null" for the absent table + for (String statement : new String[] { + "DELETE", + "DELETE FROM", + "DELETE FROM WHERE a = 1", + "DELETE FROM USING t"}) { + assertThrows(JSQLParserException.class, + () -> parserManager.parse(new StringReader(statement))); + } + } + @Test public void testDeleteWithOrderBy() throws JSQLParserException { String stmt = "DELETE FROM tablename WHERE a = 1 AND b = 1 ORDER BY col";