diff --git a/sqlparser/CHANGELOG.md b/sqlparser/CHANGELOG.md index d55e1ad5..38dc3f92 100644 --- a/sqlparser/CHANGELOG.md +++ b/sqlparser/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.29.0-dev + +- Fix false-positive warnings about `AS` aliases in subqueries used in triggers. + ## 0.28.0 - Support the `unhex` function added in sqlite 3.41.0 diff --git a/sqlparser/lib/src/analysis/steps/linting_visitor.dart b/sqlparser/lib/src/analysis/steps/linting_visitor.dart index e8640f04..1e64bcab 100644 --- a/sqlparser/lib/src/analysis/steps/linting_visitor.dart +++ b/sqlparser/lib/src/analysis/steps/linting_visitor.dart @@ -6,10 +6,24 @@ class LintingVisitor extends RecursiveVisitor { final EngineOptions options; final AnalysisContext context; - bool _isTopLevelStatement = true; + bool _isInTopLevelTriggerStatement = false; LintingVisitor(this.options, this.context); + @override + void visitBaseSelectStatement(BaseSelectStatement stmt, void arg) { + if (_isInTopLevelTriggerStatement) { + // If this select statement is used as a subqery, we're no longer in a + // top-level trigger statements. + final saved = _isInTopLevelTriggerStatement; + _isInTopLevelTriggerStatement = stmt.parent is Block; + super.visitBaseSelectStatement(stmt, arg); + _isInTopLevelTriggerStatement = saved; + } else { + super.visitBaseSelectStatement(stmt, arg); + } + } + @override void visitBinaryExpression(BinaryExpression e, void arg) { final operator = e.operator.type; @@ -141,10 +155,10 @@ class LintingVisitor extends RecursiveVisitor { @override void visitCreateTriggerStatement(CreateTriggerStatement e, void arg) { - final topLevelBefore = _isTopLevelStatement; - _isTopLevelStatement = false; + final topLevelBefore = _isInTopLevelTriggerStatement; + _isInTopLevelTriggerStatement = true; visitChildren(e, arg); - _isTopLevelStatement = topLevelBefore; + _isInTopLevelTriggerStatement = topLevelBefore; } @override @@ -172,7 +186,7 @@ class LintingVisitor extends RecursiveVisitor { @override void visitDefaultValues(DefaultValues e, void arg) { // `DEFAULT VALUES` is not supported in a trigger, see https://www.sqlite.org/lang_insert.html - if (!_isTopLevelStatement) { + if (_isInTopLevelTriggerStatement) { context.reportError( AnalysisError( type: AnalysisErrorType.synctactic, @@ -304,7 +318,7 @@ class LintingVisitor extends RecursiveVisitor { @override void visitRaiseExpression(RaiseExpression e, void arg) { - if (_isTopLevelStatement) { + if (!_isInTopLevelTriggerStatement) { context.reportError(AnalysisError( type: AnalysisErrorType.raiseMisuse, relevantNode: e, @@ -328,7 +342,7 @@ class LintingVisitor extends RecursiveVisitor { // https://www.sqlite.org/lang_returning.html#limitations_and_caveats // Returning is not allowed in triggers - if (!_isTopLevelStatement) { + if (_isInTopLevelTriggerStatement) { context.reportError(AnalysisError( type: AnalysisErrorType.illegalUseOfReturning, message: 'RETURNING is not allowed in triggers', @@ -421,7 +435,7 @@ class LintingVisitor extends RecursiveVisitor { if (parent is HasPrimarySource && parent.table == e) { // The source of a `INSERT`, `UPDATE` or `DELETE` statement must not have // an alias in `CREATE TRIGGER` statements. - if (!_isTopLevelStatement && e.as != null) { + if (_isInTopLevelTriggerStatement && e.as != null) { context.reportError(AnalysisError( type: AnalysisErrorType.synctactic, message: diff --git a/sqlparser/test/analysis/errors/syntax_error_test.dart b/sqlparser/test/analysis/errors/syntax_error_test.dart index 6490294f..9ed536c9 100644 --- a/sqlparser/test/analysis/errors/syntax_error_test.dart +++ b/sqlparser/test/analysis/errors/syntax_error_test.dart @@ -107,6 +107,14 @@ void main() { 'END;') .expectError('demo d', type: AnalysisErrorType.synctactic); }); + + test('allowed in subquery', () { + engine.analyze(''' + CREATE TRIGGER tgr AFTER DELETE ON demo BEGIN + INSERT INTO demo (content) SELECT content FROM demo AS ok; + END; + ''').expectNoError(); + }); }); }); }