mirror of https://github.com/AMT-Cheif/drift.git
Support current time literals in the sql parser
This commit is contained in:
parent
f9424470a5
commit
fbe061c84d
|
@ -4,6 +4,7 @@
|
||||||
- __Breaking__: Removed the `enableJson1` parameter on `EngineOptions`. Add a `Json1Extension` instance
|
- __Breaking__: Removed the `enableJson1` parameter on `EngineOptions`. Add a `Json1Extension` instance
|
||||||
to `enabledExtensions` instead.
|
to `enabledExtensions` instead.
|
||||||
- Parse `rowid` as a valid reference when needed (`SELECT rowid FROM tbl` is now parsed correctly)
|
- 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
|
## 0.6.0
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,8 @@ class TypeResolver {
|
||||||
} else if (l is NullLiteral) {
|
} else if (l is NullLiteral) {
|
||||||
return const ResolveResult(
|
return const ResolveResult(
|
||||||
ResolvedType(type: BasicType.nullType, nullable: true));
|
ResolvedType(type: BasicType.nullType, nullable: true));
|
||||||
|
} else if (l is TimeConstantLiteral) {
|
||||||
|
return const ResolveResult(ResolvedType(type: BasicType.text));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw StateError('Unknown literal $l');
|
throw StateError('Unknown literal $l');
|
||||||
|
|
|
@ -144,21 +144,22 @@ class TypeResolver extends RecursiveVisitor<TypeExpectation, void> {
|
||||||
@override
|
@override
|
||||||
void visitLiteral(Literal e, TypeExpectation arg) {
|
void visitLiteral(Literal e, TypeExpectation arg) {
|
||||||
ResolvedType type;
|
ResolvedType type;
|
||||||
|
var nullable = false;
|
||||||
|
|
||||||
if (e is NullLiteral) {
|
if (e is NullLiteral) {
|
||||||
type = const ResolvedType(type: BasicType.nullType, nullable: true);
|
type = const ResolvedType(type: BasicType.nullType, nullable: true);
|
||||||
session._hintNullability(e, true);
|
nullable = true;
|
||||||
} else if (e is StringLiteral) {
|
} else if (e is StringLiteral) {
|
||||||
type = e.isBinary ? const ResolvedType(type: BasicType.blob) : _textType;
|
type = e.isBinary ? const ResolvedType(type: BasicType.blob) : _textType;
|
||||||
session._hintNullability(e, false);
|
|
||||||
} else if (e is BooleanLiteral) {
|
} else if (e is BooleanLiteral) {
|
||||||
type = const ResolvedType.bool();
|
type = const ResolvedType.bool();
|
||||||
session._hintNullability(e, false);
|
|
||||||
} else if (e is NumericLiteral) {
|
} else if (e is NumericLiteral) {
|
||||||
type = e.isInt ? _intType : _realType;
|
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);
|
session._checkAndResolve(e, type, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,3 +89,24 @@ class StringLiteral extends Literal {
|
||||||
return other.isBinary == isBinary && other.value == value;
|
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');
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ abstract class AstVisitor<A, R> {
|
||||||
R visitNullLiteral(NullLiteral e, A arg);
|
R visitNullLiteral(NullLiteral e, A arg);
|
||||||
R visitBooleanLiteral(BooleanLiteral e, A arg);
|
R visitBooleanLiteral(BooleanLiteral e, A arg);
|
||||||
R visitStringLiteral(StringLiteral e, A arg);
|
R visitStringLiteral(StringLiteral e, A arg);
|
||||||
|
R visitTimeConstantLiteral(TimeConstantLiteral e, A arg);
|
||||||
|
|
||||||
R visitCastExpression(CastExpression e, A arg);
|
R visitCastExpression(CastExpression e, A arg);
|
||||||
R visitBinaryExpression(BinaryExpression 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);
|
return visitLiteral(e, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
R visitTimeConstantLiteral(TimeConstantLiteral e, A arg) {
|
||||||
|
return visitLiteral(e, arg);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
R visitReference(Reference e, A arg) {
|
R visitReference(Reference e, A arg) {
|
||||||
return visitExpression(e, arg);
|
return visitExpression(e, arg);
|
||||||
|
|
|
@ -265,7 +265,18 @@ mixin ExpressionParser on ParserBase {
|
||||||
if (_matchOne(TokenType.$false)) {
|
if (_matchOne(TokenType.$false)) {
|
||||||
return BooleanLiteral.withFalse(token);
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ Map<String, ResolveResult> _types = {
|
||||||
const ResolveResult(ResolvedType(type: BasicType.text)),
|
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 (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() {
|
void main() {
|
||||||
|
|
|
@ -29,6 +29,7 @@ const Map<String, ResolvedType> _types = {
|
||||||
'SELECT CAST(3 AS TEXT) = ?': ResolvedType(type: BasicType.text),
|
'SELECT CAST(3 AS TEXT) = ?': ResolvedType(type: BasicType.text),
|
||||||
'SELECT (3 * 4) = ?': ResolvedType(type: BasicType.int),
|
'SELECT (3 * 4) = ?': ResolvedType(type: BasicType.int),
|
||||||
'SELECT (3 / 4) = ?': ResolvedType(type: BasicType.int),
|
'SELECT (3 / 4) = ?': ResolvedType(type: BasicType.int),
|
||||||
|
'SELECT CURRENT_TIMESTAMP = ?': ResolvedType(type: BasicType.text),
|
||||||
};
|
};
|
||||||
|
|
||||||
SqlEngine _spawnEngine() {
|
SqlEngine _spawnEngine() {
|
||||||
|
|
|
@ -146,6 +146,12 @@ final Map<String, Expression> _testCases = {
|
||||||
),
|
),
|
||||||
'foo ISNULL': IsNullExpression(Reference(columnName: 'foo')),
|
'foo ISNULL': IsNullExpression(Reference(columnName: 'foo')),
|
||||||
'foo NOTNULL': IsNullExpression(Reference(columnName: 'foo'), true),
|
'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() {
|
void main() {
|
||||||
|
|
Loading…
Reference in New Issue