diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/LimitValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/LimitValidator.java index 7089d67e6d..8d001d88da 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/LimitValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/LimitValidator.java @@ -27,5 +27,8 @@ public void validate(Limit limit) { validateFeature(c, limit.isLimitAll(), Feature.limitAll); validateOptionalFeature(c, limit.getOffset(), Feature.limitOffset); } + + validateOptionalExpression(limit.getRowCount()); + validateOptionalExpression(limit.getOffset()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java index cea33e89d1..b06c8a89f5 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java @@ -15,6 +15,7 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.MySQLIndexHint; import net.sf.jsqlparser.expression.SQLServerHints; +import net.sf.jsqlparser.expression.WindowDefinition; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.imprt.Import; @@ -152,10 +153,17 @@ public Void visit(PlainSelect plainSelect, S context) { validateOptionalFromItems(plainSelect.getIntoTables()); validateOptionalJoins(plainSelect.getJoins()); - // to correctly recognize aliased tables - // @todo: fix this properly, I don't understand functional syntax - // validateOptionalList(plainSelect.getSelectItems(), () -> this, SelectItem::accept, - // context); + // after the FROM items, to correctly recognize aliased tables + if (plainSelect.getDistinct() != null + && isNotEmpty(plainSelect.getDistinct().getOnSelectItems())) { + plainSelect.getDistinct().getOnSelectItems() + .forEach(item -> item.accept(this, context)); + } + validateOptional(plainSelect.getTop(), + top -> validateOptionalExpression(top.getExpression())); + if (isNotEmpty(plainSelect.getSelectItems())) { + plainSelect.getSelectItems().forEach(item -> item.accept(this, context)); + } validateOptionalExpression(plainSelect.getPreWhere()); validateOptionalExpression(plainSelect.getWhere()); @@ -168,6 +176,13 @@ public Void visit(PlainSelect plainSelect, S context) { } validateOptionalExpression(plainSelect.getHaving()); + validateOptionalExpression(plainSelect.getQualify()); + if (isNotEmpty(plainSelect.getWindowDefinitions())) { + for (WindowDefinition windowDefinition : plainSelect.getWindowDefinitions()) { + validateOptionalExpressions(windowDefinition.getPartitionExpressionList()); + validateOptionalOrderByElements(windowDefinition.getOrderByElements()); + } + } validateOptionalOrderByElements(plainSelect.getOrderByElements()); validateOptionalInterpolate(plainSelect.getInterpolate()); validateOptionalOption(plainSelect.getOption()); @@ -332,6 +347,8 @@ public void validateOffset(Offset offset) { validateFeature(c, Feature.offset); validateOptionalFeature(c, offset.getOffsetParam(), Feature.offsetParam); } + + validateOptionalExpression(offset.getOffset()); } public void validateFetch(Fetch fetch) { @@ -341,7 +358,7 @@ public void validateFetch(Fetch fetch) { validateFeature(c, !fetch.isFetchParamFirst(), Feature.fetchNext); } - validateOptionalExpression(fetch.getFetchJdbcParameter()); + validateOptionalExpression(fetch.getExpression()); } public void validateOptionalJoins(List joins) { diff --git a/src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java b/src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java index 7c21680f06..1d0aaa81fa 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java @@ -156,4 +156,12 @@ public void testValidationMetadataSelectWithColumnsAndAlias2() new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } + + @Test + public void testValidationMetadataSelectListError() throws JSQLParserException, SQLException { + String sql = "select my.id, my.price from mytable as my"; + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + validateMetadata(sql, 1, 1, meta, true, "my.price"); + } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/SelectValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/SelectValidatorTest.java index 9c372310da..c6ffec2fd8 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/SelectValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/SelectValidatorTest.java @@ -246,6 +246,29 @@ public void testValidateTableFunctionArguments(String sql) { validateNotAllowed(sql, 1, 1, SELECT_WITH_TABLE_FUNCTIONS, Feature.jdbcParameter); } + @ParameterizedTest + @ValueSource(strings = {"SELECT upper(a) FROM t", + "SELECT DISTINCT ON (upper(a)) a FROM t", + "SELECT TOP (upper(a)) a FROM t", + "SELECT a FROM t QUALIFY upper(a) = 'X'", + "SELECT a FROM t WINDOW w AS (PARTITION BY upper(a))", + "SELECT a FROM t WINDOW w AS (ORDER BY upper(a))", + "SELECT a FROM t LIMIT upper(a)", + "SELECT a FROM t LIMIT 1 OFFSET upper(a)", + "SELECT a FROM t OFFSET upper(a) ROWS", + "SELECT a FROM t FETCH FIRST upper(a) ROWS ONLY", + "SELECT a FROM t UNION SELECT b FROM u LIMIT upper(a)"}) + public void testValidateFunctionOutsideWhere(String sql) { + validateNotAllowed(sql, 1, 1, + new FeaturesAllowed(Feature.values()).remove(Feature.function), Feature.function); + } + + @Test + public void testValidateSubSelectInSelectList() { + validateNotAllowed("SELECT (SELECT a FROM t FOR UPDATE)", 1, 1, FeaturesAllowed.SELECT, + Feature.selectForUpdate); + } + @Test public void testValidateLateral() throws JSQLParserException { validateNoErrors(