Skip to content

Commit 4127cb3

Browse files
fix: validate select items and skipped clauses in SelectValidator (#2879)
SelectValidator never validated the select list (the call was commented out), nor DISTINCT ON, TOP, QUALIFY, WINDOW definitions and the LIMIT, OFFSET and FETCH row counts, so no capability saw the expressions there. They are now validated like WHERE, with the select list after the FROM items so table aliases resolve.
1 parent 9703ff4 commit 4127cb3

4 files changed

Lines changed: 56 additions & 5 deletions

File tree

‎src/main/java/net/sf/jsqlparser/util/validation/validator/LimitValidator.java‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,8 @@ public void validate(Limit limit) {
2727
validateFeature(c, limit.isLimitAll(), Feature.limitAll);
2828
validateOptionalFeature(c, limit.getOffset(), Feature.limitOffset);
2929
}
30+
31+
validateOptionalExpression(limit.getRowCount());
32+
validateOptionalExpression(limit.getOffset());
3033
}
3134
}

‎src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java‎

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import net.sf.jsqlparser.expression.Expression;
1616
import net.sf.jsqlparser.expression.MySQLIndexHint;
1717
import net.sf.jsqlparser.expression.SQLServerHints;
18+
import net.sf.jsqlparser.expression.WindowDefinition;
1819
import net.sf.jsqlparser.parser.feature.Feature;
1920
import net.sf.jsqlparser.schema.Table;
2021
import net.sf.jsqlparser.statement.imprt.Import;
@@ -152,10 +153,17 @@ public <S> Void visit(PlainSelect plainSelect, S context) {
152153
validateOptionalFromItems(plainSelect.getIntoTables());
153154
validateOptionalJoins(plainSelect.getJoins());
154155

155-
// to correctly recognize aliased tables
156-
// @todo: fix this properly, I don't understand functional syntax
157-
// validateOptionalList(plainSelect.getSelectItems(), () -> this, SelectItem::accept,
158-
// context);
156+
// after the FROM items, to correctly recognize aliased tables
157+
if (plainSelect.getDistinct() != null
158+
&& isNotEmpty(plainSelect.getDistinct().getOnSelectItems())) {
159+
plainSelect.getDistinct().getOnSelectItems()
160+
.forEach(item -> item.accept(this, context));
161+
}
162+
validateOptional(plainSelect.getTop(),
163+
top -> validateOptionalExpression(top.getExpression()));
164+
if (isNotEmpty(plainSelect.getSelectItems())) {
165+
plainSelect.getSelectItems().forEach(item -> item.accept(this, context));
166+
}
159167

160168
validateOptionalExpression(plainSelect.getPreWhere());
161169
validateOptionalExpression(plainSelect.getWhere());
@@ -168,6 +176,13 @@ public <S> Void visit(PlainSelect plainSelect, S context) {
168176
}
169177

170178
validateOptionalExpression(plainSelect.getHaving());
179+
validateOptionalExpression(plainSelect.getQualify());
180+
if (isNotEmpty(plainSelect.getWindowDefinitions())) {
181+
for (WindowDefinition windowDefinition : plainSelect.getWindowDefinitions()) {
182+
validateOptionalExpressions(windowDefinition.getPartitionExpressionList());
183+
validateOptionalOrderByElements(windowDefinition.getOrderByElements());
184+
}
185+
}
171186
validateOptionalOrderByElements(plainSelect.getOrderByElements());
172187
validateOptionalInterpolate(plainSelect.getInterpolate());
173188
validateOptionalOption(plainSelect.getOption());
@@ -332,6 +347,8 @@ public void validateOffset(Offset offset) {
332347
validateFeature(c, Feature.offset);
333348
validateOptionalFeature(c, offset.getOffsetParam(), Feature.offsetParam);
334349
}
350+
351+
validateOptionalExpression(offset.getOffset());
335352
}
336353

337354
public void validateFetch(Fetch fetch) {
@@ -341,7 +358,7 @@ public void validateFetch(Fetch fetch) {
341358
validateFeature(c, !fetch.isFetchParamFirst(), Feature.fetchNext);
342359
}
343360

344-
validateOptionalExpression(fetch.getFetchJdbcParameter());
361+
validateOptionalExpression(fetch.getExpression());
345362
}
346363

347364
public void validateOptionalJoins(List<Join> joins) {

‎src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,12 @@ public void testValidationMetadataSelectWithColumnsAndAlias2()
156156
new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE);
157157
validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors
158158
}
159+
160+
@Test
161+
public void testValidationMetadataSelectListError() throws JSQLParserException, SQLException {
162+
String sql = "select my.id, my.price from mytable as my";
163+
JdbcDatabaseMetaDataCapability meta =
164+
new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE);
165+
validateMetadata(sql, 1, 1, meta, true, "my.price");
166+
}
159167
}

‎src/test/java/net/sf/jsqlparser/util/validation/validator/SelectValidatorTest.java‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,29 @@ public void testValidateTableFunctionArguments(String sql) {
246246
validateNotAllowed(sql, 1, 1, SELECT_WITH_TABLE_FUNCTIONS, Feature.jdbcParameter);
247247
}
248248

249+
@ParameterizedTest
250+
@ValueSource(strings = {"SELECT upper(a) FROM t",
251+
"SELECT DISTINCT ON (upper(a)) a FROM t",
252+
"SELECT TOP (upper(a)) a FROM t",
253+
"SELECT a FROM t QUALIFY upper(a) = 'X'",
254+
"SELECT a FROM t WINDOW w AS (PARTITION BY upper(a))",
255+
"SELECT a FROM t WINDOW w AS (ORDER BY upper(a))",
256+
"SELECT a FROM t LIMIT upper(a)",
257+
"SELECT a FROM t LIMIT 1 OFFSET upper(a)",
258+
"SELECT a FROM t OFFSET upper(a) ROWS",
259+
"SELECT a FROM t FETCH FIRST upper(a) ROWS ONLY",
260+
"SELECT a FROM t UNION SELECT b FROM u LIMIT upper(a)"})
261+
public void testValidateFunctionOutsideWhere(String sql) {
262+
validateNotAllowed(sql, 1, 1,
263+
new FeaturesAllowed(Feature.values()).remove(Feature.function), Feature.function);
264+
}
265+
266+
@Test
267+
public void testValidateSubSelectInSelectList() {
268+
validateNotAllowed("SELECT (SELECT a FROM t FOR UPDATE)", 1, 1, FeaturesAllowed.SELECT,
269+
Feature.selectForUpdate);
270+
}
271+
249272
@Test
250273
public void testValidateLateral() throws JSQLParserException {
251274
validateNoErrors(

0 commit comments

Comments
 (0)