From e5d0051f5e7064cd192dba50630c6e77750fce9d Mon Sep 17 00:00:00 2001 From: David Hayes Date: Fri, 24 Jul 2026 13:06:00 +0100 Subject: [PATCH 1/2] [Fix] #2443 - NPE In TableNamesFinder with AnalyticExpression If you attempt to tree walk an AnalyticExpression in TableNamesFinder with an SQL that has a window function without a range and without an offset, such as `SELECT c, SUM(COUNT(*)) OVER (ORDER BY c ASC ROWS UNBOUNDED PRECEDING) FROM tbl GROUP BY c`, an NPE is thrown. This adds defensive checks around the range and offset expressions being null. --- .../sf/jsqlparser/util/TablesNamesFinder.java | 19 +++++++++++-------- .../util/TablesNamesFinderTest.java | 8 ++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 09ca9faba..9cbdd36b3 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -766,17 +766,20 @@ public Void visit(AnalyticExpression analytic, S context) { } if (analytic.getWindowElement() != null) { - if (analytic.getWindowElement().getRange().getStart().getExpression() != null) { - analytic.getWindowElement().getRange().getStart().getExpression().accept(this, - context); - } - if (analytic.getWindowElement().getRange().getEnd().getExpression() != null) { - analytic.getWindowElement().getRange().getEnd().getExpression().accept(this, - context); + if (analytic.getWindowElement().getRange() != null) { + if (analytic.getWindowElement().getRange().getStart().getExpression() != null) { + analytic.getWindowElement().getRange().getStart().getExpression().accept(this, + context); + } + if (analytic.getWindowElement().getRange().getEnd().getExpression() != null) { + analytic.getWindowElement().getRange().getEnd().getExpression().accept(this, + context); + } } - if (analytic.getWindowElement().getOffset() != null) { + if (analytic.getWindowElement().getOffset() != null && analytic.getWindowElement().getOffset().getExpression() != null) { analytic.getWindowElement().getOffset().getExpression().accept(this, context); } + } return null; } diff --git a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java index 44a27624c..8581a0e59 100644 --- a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java +++ b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java @@ -771,4 +771,12 @@ void testJsonTable() throws JSQLParserException { } + @Test + void testWindowExpressionWithNoRangeAndNoOffsetDoesNotThrowException() { + String sqlStr = "SELECT c, SUM(COUNT(*)) OVER (ORDER BY c ASC ROWS UNBOUNDED PRECEDING) FROM tbl GROUP BY c"; + + assertThatCode(() -> TablesNamesFinder.findTables(sqlStr)) + .doesNotThrowAnyException(); + } + } From 14e3a278b1d39b7dc59ba7d5b2e354da016df611 Mon Sep 17 00:00:00 2001 From: David Hayes Date: Fri, 24 Jul 2026 14:40:29 +0100 Subject: [PATCH 2/2] More aggressive NPE protection --- src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 9cbdd36b3..f2e6105ff 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -767,11 +767,13 @@ public Void visit(AnalyticExpression analytic, S context) { if (analytic.getWindowElement() != null) { if (analytic.getWindowElement().getRange() != null) { - if (analytic.getWindowElement().getRange().getStart().getExpression() != null) { + if (analytic.getWindowElement().getRange().getStart() != null + && analytic.getWindowElement().getRange().getStart().getExpression() != null) { analytic.getWindowElement().getRange().getStart().getExpression().accept(this, context); } - if (analytic.getWindowElement().getRange().getEnd().getExpression() != null) { + if (analytic.getWindowElement().getRange().getEnd() != null + && analytic.getWindowElement().getRange().getEnd().getExpression() != null) { analytic.getWindowElement().getRange().getEnd().getExpression().accept(this, context); }