Fix false-positive trigger syntax error (#2360)

This commit is contained in:
Simon Binder 2023-03-26 21:44:12 +02:00
parent a6549425ef
commit c38e9cc6c0
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
3 changed files with 34 additions and 8 deletions

View File

@ -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

View File

@ -6,10 +6,24 @@ class LintingVisitor extends RecursiveVisitor<void, void> {
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<void, void> {
@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<void, void> {
@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<void, void> {
@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<void, void> {
// 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<void, void> {
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:

View File

@ -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();
});
});
});
}