Fix analyzer crash at CTE (#255)

This commit is contained in:
Simon Binder 2019-11-24 14:46:20 +01:00
parent a1f9e7ce13
commit bb1fcc1590
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
7 changed files with 100 additions and 7 deletions

View File

@ -966,6 +966,13 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
readsFrom: {config}).map(_rowToReadRowIdResult);
}
Selectable<int> test() {
return customSelectQuery(
'WITH RECURSIVE\n cnt(x) AS (\n SELECT 1\n UNION ALL\n SELECT x+1 FROM cnt\n LIMIT 1000000\n )\n SELECT x FROM cnt',
variables: [],
readsFrom: {}).map((QueryRow row) => row.readInt('x'));
}
Future<int> writeConfig(String key, String value) {
return customInsert(
'REPLACE INTO config VALUES (:key, :value)',

View File

@ -31,4 +31,13 @@ readConfig: SELECT * FROM config WHERE config_key = ?;
readMultiple: SELECT * FROM config WHERE config_key IN ? ORDER BY $clause;
readDynamic: SELECT * FROM config WHERE $predicate;
readRowId: SELECT oid, * FROM config WHERE _rowid_ = $expr;
readRowId: SELECT oid, * FROM config WHERE _rowid_ = $expr;
cfeTest: WITH RECURSIVE
cnt(x) AS (
SELECT 1
UNION ALL
SELECT x+1 FROM cnt
LIMIT 1000000
)
SELECT x FROM cnt;

View File

@ -18,9 +18,9 @@ class ReferencedTablesVisitor extends RecursiveVisitor<void> {
@override
void visitQueryable(Queryable e) {
if (e is TableReference) {
final table = e.resolved as Table;
if (table != null) {
foundTables.add(table);
final resolved = e.resolved;
if (resolved != null && resolved is Table) {
foundTables.add(resolved);
}
}

View File

@ -156,8 +156,13 @@ class QueryHandler {
} else if (c is ExpressionColumn) {
final expression = c.expression;
if (expression is Reference) {
return expression.resolved as TableColumn;
final resolved = expression.resolved;
if (resolved is Column) {
return _toTableColumn(resolved);
}
}
} else if (c is DelegatedColumn) {
return _toTableColumn(c.innerColumn);
}
return null;
}

View File

@ -0,0 +1,66 @@
import 'package:build/build.dart';
import 'package:moor_generator/src/analyzer/runner/file_graph.dart';
import 'package:moor_generator/src/analyzer/runner/results.dart';
import 'package:moor_generator/src/analyzer/runner/task.dart';
import 'package:moor_generator/src/analyzer/session.dart';
import 'package:moor_generator/src/model/specified_column.dart';
import 'package:moor_generator/src/model/sql_query.dart';
import 'package:test/test.dart';
import '../../utils/test_backend.dart';
void main() {
TestBackend backend;
MoorSession session;
Task task;
setUpAll(() {
backend = TestBackend(
{
AssetId.parse('foo|lib/test.moor'): r'''
test:
WITH RECURSIVE
cnt(x) AS (
SELECT 1
UNION ALL
SELECT x+1 FROM cnt
LIMIT 1000000
)
SELECT x FROM cnt;
''',
},
);
session = backend.session;
});
setUp(() async {
final backendTask = backend.startTask(Uri.parse('package:foo/test.moor'));
task = session.startTask(backendTask);
await task.runTask();
});
tearDownAll(() {
backend.finish();
});
test('recognizes CFE clause', () {
final file = session.registerFile(Uri.parse('package:foo/test.moor'));
expect(file.state, FileState.analyzed);
expect(file.errors.errors, isEmpty);
final result = file.currentResult as ParsedMoorFile;
final query = result.resolvedQueries.single as SqlSelectQuery;
expect(query.name, 'test');
expect(query.variables, isEmpty);
expect(query.declaredInMoorFile, isTrue);
expect(query.readsFrom, isEmpty);
final resultSet = query.resultSet;
expect(resultSet.singleColumn, isTrue);
expect(resultSet.needsOwnClass, isFalse);
expect(resultSet.columns.map(resultSet.dartNameFor), ['x']);
expect(resultSet.columns.map((c) => c.type), [ColumnType.integer]);
});
}

View File

@ -31,6 +31,10 @@ abstract class TableOrSubquery extends Queryable {}
///
/// This is both referencable (if we have SELECT * FROM table t), other parts
/// of the select statement can access "t") and a reference owner (the table).
///
/// Note that this doesn't necessarily resolve to a result set. It could also
/// resolve to a common table expression or anything else defining a result
/// set.
class TableReference extends TableOrSubquery
with ReferenceOwner
implements Renamable, ResolvesToResultSet, VisibleToChildren {

View File

@ -55,8 +55,10 @@ void main() {
expect(context.errors, isEmpty);
final select = context.root as SelectStatement;
final column = context.typeOf(select.resolvedColumns.single);
final column = select.resolvedColumns.single;
final type = context.typeOf(column);
expect(column.type, const ResolvedType(type: BasicType.int));
expect(type.type, const ResolvedType(type: BasicType.int));
expect(column.name, 'x');
});
}