Support current time literals in the sql parser

This commit is contained in:
Simon Binder 2020-02-01 13:18:53 +01:00
parent f9424470a5
commit fbe061c84d
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
9 changed files with 56 additions and 5 deletions

View File

@ -4,6 +4,7 @@
- __Breaking__: Removed the `enableJson1` parameter on `EngineOptions`. Add a `Json1Extension` instance
to `enabledExtensions` instead.
- Parse `rowid` as a valid reference when needed (`SELECT rowid FROM tbl` is now parsed correctly)
- Parse `CURRENT_TIME`, `CURRENT_DATE` and `CURRENT_TIMESTAMP`
## 0.6.0

View File

@ -161,6 +161,8 @@ class TypeResolver {
} else if (l is NullLiteral) {
return const ResolveResult(
ResolvedType(type: BasicType.nullType, nullable: true));
} else if (l is TimeConstantLiteral) {
return const ResolveResult(ResolvedType(type: BasicType.text));
}
throw StateError('Unknown literal $l');

View File

@ -144,21 +144,22 @@ class TypeResolver extends RecursiveVisitor<TypeExpectation, void> {
@override
void visitLiteral(Literal e, TypeExpectation arg) {
ResolvedType type;
var nullable = false;
if (e is NullLiteral) {
type = const ResolvedType(type: BasicType.nullType, nullable: true);
session._hintNullability(e, true);
nullable = true;
} else if (e is StringLiteral) {
type = e.isBinary ? const ResolvedType(type: BasicType.blob) : _textType;
session._hintNullability(e, false);
} else if (e is BooleanLiteral) {
type = const ResolvedType.bool();
session._hintNullability(e, false);
} else if (e is NumericLiteral) {
type = e.isInt ? _intType : _realType;
session._hintNullability(e, false);
} else if (e is TimeConstantLiteral) {
type = _textType;
}
session._hintNullability(e, nullable);
session._checkAndResolve(e, type, arg);
}

View File

@ -89,3 +89,24 @@ class StringLiteral extends Literal {
return other.isBinary == isBinary && other.value == value;
}
}
enum TimeConstantKind { currentTime, currentDate, currentTimestamp }
class TimeConstantLiteral extends Literal {
final TimeConstantKind kind;
TimeConstantLiteral(this.kind, Token keyword) : super(keyword);
@override
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
return visitor.visitTimeConstantLiteral(this, arg);
}
@override
bool contentEquals(TimeConstantLiteral other) {
return other.kind == kind;
}
@override
dynamic get value => throw UnimplementedError('TimeConstantLiteral.value');
}

View File

@ -34,6 +34,7 @@ abstract class AstVisitor<A, R> {
R visitNullLiteral(NullLiteral e, A arg);
R visitBooleanLiteral(BooleanLiteral e, A arg);
R visitStringLiteral(StringLiteral e, A arg);
R visitTimeConstantLiteral(TimeConstantLiteral e, A arg);
R visitCastExpression(CastExpression e, A arg);
R visitBinaryExpression(BinaryExpression e, A arg);
@ -325,6 +326,11 @@ class RecursiveVisitor<A, R> implements AstVisitor<A, R> {
return visitLiteral(e, arg);
}
@override
R visitTimeConstantLiteral(TimeConstantLiteral e, A arg) {
return visitLiteral(e, arg);
}
@override
R visitReference(Reference e, A arg) {
return visitExpression(e, arg);

View File

@ -265,7 +265,18 @@ mixin ExpressionParser on ParserBase {
if (_matchOne(TokenType.$false)) {
return BooleanLiteral.withFalse(token);
}
// todo CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP
const timeLiterals = {
TokenType.currentTime: TimeConstantKind.currentTime,
TokenType.currentDate: TimeConstantKind.currentDate,
TokenType.currentTimestamp: TimeConstantKind.currentTimestamp,
};
if (_match(timeLiterals.keys)) {
final token = _previous;
return TimeConstantLiteral(timeLiterals[token.type], token);
}
return null;
}

View File

@ -34,6 +34,8 @@ Map<String, ResolveResult> _types = {
const ResolveResult(ResolvedType(type: BasicType.text)),
'SELECT (3 * 4) = ?': const ResolveResult(ResolvedType(type: BasicType.int)),
'SELECT (3 / 4) = ?': const ResolveResult(ResolvedType(type: BasicType.int)),
'SELECT CURRENT_TIME = ?':
const ResolveResult(ResolvedType(type: BasicType.text)),
};
void main() {

View File

@ -29,6 +29,7 @@ const Map<String, ResolvedType> _types = {
'SELECT CAST(3 AS TEXT) = ?': ResolvedType(type: BasicType.text),
'SELECT (3 * 4) = ?': ResolvedType(type: BasicType.int),
'SELECT (3 / 4) = ?': ResolvedType(type: BasicType.int),
'SELECT CURRENT_TIMESTAMP = ?': ResolvedType(type: BasicType.text),
};
SqlEngine _spawnEngine() {

View File

@ -146,6 +146,12 @@ final Map<String, Expression> _testCases = {
),
'foo ISNULL': IsNullExpression(Reference(columnName: 'foo')),
'foo NOTNULL': IsNullExpression(Reference(columnName: 'foo'), true),
'CURRENT_TIME': TimeConstantLiteral(
TimeConstantKind.currentTime, token(TokenType.currentTime)),
'CURRENT_TIMESTAMP': TimeConstantLiteral(
TimeConstantKind.currentTimestamp, token(TokenType.currentTimestamp)),
'CURRENT_DATE': TimeConstantLiteral(
TimeConstantKind.currentDate, token(TokenType.currentDate)),
};
void main() {