added rtree support

This commit is contained in:
Fabian Freund 2022-08-23 16:33:23 +03:00
parent c44578da60
commit d1e623a0c6
6 changed files with 111 additions and 0 deletions

View File

@ -275,4 +275,8 @@ enum SqlModule {
///
/// [math funs]: https://www.sqlite.org/lang_mathfunc.html
math,
/// Enables support for the rtree module and its functions when parsing sql
/// queries.
rtree,
}

View File

@ -140,6 +140,7 @@ const _$SqlModuleEnumMap = {
SqlModule.fts5: 'fts5',
SqlModule.moor_ffi: 'moor_ffi',
SqlModule.math: 'math',
SqlModule.rtree: 'rtree',
};
DialectOptions _$DialectOptionsFromJson(Map json) => $checkedCreate(

View File

@ -45,6 +45,7 @@ class MoorSession {
if (options.hasModule(SqlModule.json1)) const Json1Extension(),
if (options.hasModule(SqlModule.moor_ffi)) const MoorFfiExtension(),
if (options.hasModule(SqlModule.math)) const BuiltInMathExtension(),
if (options.hasModule(SqlModule.rtree)) const RTreeExtension(),
],
version: options.sqliteVersion,
);

View File

@ -7,6 +7,7 @@ export 'src/ast/ast.dart';
export 'src/engine/module/fts5.dart' show Fts5Extension;
export 'src/engine/module/json1.dart' show Json1Extension;
export 'src/engine/module/math.dart' show BuiltInMathExtension;
export 'src/engine/module/rtree.dart' show RTreeExtension;
export 'src/engine/module/module.dart';
export 'src/engine/options.dart';
export 'src/engine/sql_engine.dart';

View File

@ -0,0 +1,39 @@
import 'package:sqlparser/sqlparser.dart';
class RTreeExtension implements Extension {
const RTreeExtension();
@override
void register(SqlEngine engine) {
engine.registerModule(_RTreeModule());
}
}
class _RTreeModule extends Module {
_RTreeModule() : super('rtree');
@override
Table parseTable(CreateVirtualTableStatement stmt) {
final columnNames = stmt.argumentContent;
if (columnNames.length < 3 || columnNames.length > 11) {
throw ArgumentError(
'An rtree virtual table is supposed to have between 3 and 11 columns');
}
if (columnNames.length.isEven) {
throw ArgumentError(
'The rtree has not been initialized with a proper dimension. '
'Required is an index, follwoed by a even number of min/max pairs');
}
return Table(name: stmt.tableName, resolvedColumns: [
for (final columnName in columnNames)
//First column is always an integer primary key
//followed by n floating point values
(columnName == columnNames.first)
? TableColumn(columnName, const ResolvedType(type: BasicType.int))
: TableColumn(columnName, const ResolvedType(type: BasicType.real))
]);
}
}

View File

@ -0,0 +1,65 @@
import 'package:sqlparser/sqlparser.dart';
import 'package:test/test.dart';
final _rtreeOptions =
EngineOptions(enabledExtensions: const [RTreeExtension()]);
void main() {
group('creating rtree tables', () {
final engine = SqlEngine(_rtreeOptions);
test('can create rtree table', () {
final result = engine.analyze('''
CREATE VIRTUAL TABLE demo_index USING rtree(
id, -- Integer primary key
minX, maxX, -- Minimum and maximum X coordinate
minY, maxY -- Minimum and maximum Y coordinate
);''');
final table = const SchemaFromCreateTable()
.read(result.root as TableInducingStatement);
expect(table.name, 'demo_index');
final columns = table.resultColumns;
expect(columns, hasLength(5));
expect(columns.first.type.type, equals(BasicType.int));
expect(columns.last.type.type, equals(BasicType.real));
});
});
group('type inference for function arguments', () {
late SqlEngine engine;
setUp(() {
engine = SqlEngine(_rtreeOptions);
// add an fts5 table for the following queries
final result = engine.analyze('''
CREATE VIRTUAL TABLE demo_index USING rtree(
id, -- Integer primary key
minX, maxX, -- Minimum and maximum X coordinate
minY, maxY -- Minimum and maximum Y coordinate
);''');
engine.registerTable(const SchemaFromCreateTable()
.read(result.root as TableInducingStatement));
});
test('insert', () {
final result = engine.analyze('INSERT INTO demo_index VALUES '
'(28215, -80.781227, -80.604706, 35.208813, 35.297367);');
expect(result.errors, isEmpty);
});
test('select', () {
final result = engine.analyze('''
SELECT A.* FROM demo_index AS A, demo_index AS B
WHERE A.maxX>=B.minX AND A.minX<=B.maxX
AND A.maxY>=B.minY AND A.minY<=B.maxY
AND B.id=28269;''');
final columns = (result.root as SelectStatement).resolvedColumns;
expect(result.errors, isEmpty);
expect(columns, hasLength(5));
});
});
}