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 ## 0.28.0
- Support the `unhex` function added in sqlite 3.41.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 EngineOptions options;
final AnalysisContext context; final AnalysisContext context;
bool _isTopLevelStatement = true; bool _isInTopLevelTriggerStatement = false;
LintingVisitor(this.options, this.context); 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 @override
void visitBinaryExpression(BinaryExpression e, void arg) { void visitBinaryExpression(BinaryExpression e, void arg) {
final operator = e.operator.type; final operator = e.operator.type;
@ -141,10 +155,10 @@ class LintingVisitor extends RecursiveVisitor<void, void> {
@override @override
void visitCreateTriggerStatement(CreateTriggerStatement e, void arg) { void visitCreateTriggerStatement(CreateTriggerStatement e, void arg) {
final topLevelBefore = _isTopLevelStatement; final topLevelBefore = _isInTopLevelTriggerStatement;
_isTopLevelStatement = false; _isInTopLevelTriggerStatement = true;
visitChildren(e, arg); visitChildren(e, arg);
_isTopLevelStatement = topLevelBefore; _isInTopLevelTriggerStatement = topLevelBefore;
} }
@override @override
@ -172,7 +186,7 @@ class LintingVisitor extends RecursiveVisitor<void, void> {
@override @override
void visitDefaultValues(DefaultValues e, void arg) { void visitDefaultValues(DefaultValues e, void arg) {
// `DEFAULT VALUES` is not supported in a trigger, see https://www.sqlite.org/lang_insert.html // `DEFAULT VALUES` is not supported in a trigger, see https://www.sqlite.org/lang_insert.html
if (!_isTopLevelStatement) { if (_isInTopLevelTriggerStatement) {
context.reportError( context.reportError(
AnalysisError( AnalysisError(
type: AnalysisErrorType.synctactic, type: AnalysisErrorType.synctactic,
@ -304,7 +318,7 @@ class LintingVisitor extends RecursiveVisitor<void, void> {
@override @override
void visitRaiseExpression(RaiseExpression e, void arg) { void visitRaiseExpression(RaiseExpression e, void arg) {
if (_isTopLevelStatement) { if (!_isInTopLevelTriggerStatement) {
context.reportError(AnalysisError( context.reportError(AnalysisError(
type: AnalysisErrorType.raiseMisuse, type: AnalysisErrorType.raiseMisuse,
relevantNode: e, relevantNode: e,
@ -328,7 +342,7 @@ class LintingVisitor extends RecursiveVisitor<void, void> {
// https://www.sqlite.org/lang_returning.html#limitations_and_caveats // https://www.sqlite.org/lang_returning.html#limitations_and_caveats
// Returning is not allowed in triggers // Returning is not allowed in triggers
if (!_isTopLevelStatement) { if (_isInTopLevelTriggerStatement) {
context.reportError(AnalysisError( context.reportError(AnalysisError(
type: AnalysisErrorType.illegalUseOfReturning, type: AnalysisErrorType.illegalUseOfReturning,
message: 'RETURNING is not allowed in triggers', message: 'RETURNING is not allowed in triggers',
@ -421,7 +435,7 @@ class LintingVisitor extends RecursiveVisitor<void, void> {
if (parent is HasPrimarySource && parent.table == e) { if (parent is HasPrimarySource && parent.table == e) {
// The source of a `INSERT`, `UPDATE` or `DELETE` statement must not have // The source of a `INSERT`, `UPDATE` or `DELETE` statement must not have
// an alias in `CREATE TRIGGER` statements. // an alias in `CREATE TRIGGER` statements.
if (!_isTopLevelStatement && e.as != null) { if (_isInTopLevelTriggerStatement && e.as != null) {
context.reportError(AnalysisError( context.reportError(AnalysisError(
type: AnalysisErrorType.synctactic, type: AnalysisErrorType.synctactic,
message: message:

View File

@ -107,6 +107,14 @@ void main() {
'END;') 'END;')
.expectError('demo d', type: AnalysisErrorType.synctactic); .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();
});
}); });
}); });
} }