Analysis support for table-valued functions

This commit is contained in:
Simon Binder 2020-01-26 14:04:35 +01:00
parent 5622ed5c43
commit c82bff8c97
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
5 changed files with 31 additions and 13 deletions

View File

@ -136,16 +136,9 @@ class ColumnResolver extends RecursiveVisitor<void, void> {
} }
}, },
isTableFunction: (function) { isTableFunction: (function) {
final functions = context.engineOptions.addedFunctions; final handler = context
final lowercaseName = function.name.toLowerCase(); .engineOptions.addedTableFunctions[function.name.toLowerCase()];
ResultSet resolved; final resolved = handler?.resolveTableValued(context, function);
if (functions.containsKey(lowercaseName)) {
final handler = functions[lowercaseName];
if (handler is TableValuedFunctionHandler) {
resolved = handler.resolveTableValued(context, function);
}
}
if (resolved == null) { if (resolved == null) {
context.reportError(AnalysisError( context.reportError(AnalysisError(

View File

@ -1,7 +1,11 @@
part of '../ast.dart'; part of '../ast.dart';
/// Interface for function calls, either a [FunctionExpression] or a /// Interface for function calls.
/// [AggregateExpression]. ///
/// Functions that resolve to an [Expression] are subclasses of
/// [ExpressionInvocation], like [FunctionExpression] or [AggregateExpression].
/// There are invocation that don't resolve to an expression, notably
/// [TableValuedFunction].
abstract class SqlInvocation implements AstNode { abstract class SqlInvocation implements AstNode {
/// The name of the function being called /// The name of the function being called
String get name; String get name;

View File

@ -47,7 +47,12 @@ abstract class FunctionHandler {
void reportErrors(SqlInvocation call, AnalysisContext context) {} void reportErrors(SqlInvocation call, AnalysisContext context) {}
} }
abstract class TableValuedFunctionHandler implements FunctionHandler { /// Interface for a handler which can resolve the result set of a table-valued
/// function.
abstract class TableValuedFunctionHandler {
/// The name of the table-valued function implemented by this handler.
String get functionName;
/// Resolve the result set of a table-valued function. /// Resolve the result set of a table-valued function.
/// ///
/// Should return null when the result set can't be resolved. /// Should return null when the result set can't be resolved.

View File

@ -16,8 +16,14 @@ class EngineOptions {
final List<Extension> enabledExtensions; final List<Extension> enabledExtensions;
final List<FunctionHandler> _addedFunctionHandlers = []; final List<FunctionHandler> _addedFunctionHandlers = [];
/// A map from lowercase function names to the associated handler.
final Map<String, FunctionHandler> addedFunctions = {}; final Map<String, FunctionHandler> addedFunctions = {};
/// A map from lowercase function names (where the function is a table-valued
/// function) to the associated handler.
final Map<String, TableValuedFunctionHandler> addedTableFunctions = {};
EngineOptions({ EngineOptions({
this.useMoorExtensions = false, this.useMoorExtensions = false,
this.enableJson1 = false, this.enableJson1 = false,
@ -32,4 +38,8 @@ class EngineOptions {
addedFunctions[function.toLowerCase()] = handler; addedFunctions[function.toLowerCase()] = handler;
} }
} }
void addTableValuedFunctionHandler(TableValuedFunctionHandler handler) {
addedTableFunctions[handler.functionName.toLowerCase()] = handler;
}
} }

View File

@ -75,6 +75,12 @@ class SqlEngine {
options.addFunctionHandler(handler); options.addFunctionHandler(handler);
} }
/// Registers the [handler], which can infer result sets for a table-valued
/// function.
void registerTableValuedFunctionHandler(TableValuedFunctionHandler handler) {
options.addTableValuedFunctionHandler(handler);
}
ReferenceScope _constructRootScope({ReferenceScope parent}) { ReferenceScope _constructRootScope({ReferenceScope parent}) {
final scope = parent == null ? ReferenceScope(null) : parent.createChild(); final scope = parent == null ? ReferenceScope(null) : parent.createChild();
for (final table in knownTables) { for (final table in knownTables) {