Skip to content

Commit 1081f4a

Browse files
committed
fix: 3 SQL parser bugs — scientific notation, missing window functions, frame end default
- Lexer now handles scientific notation (1e10, 1.5e-3, 3E+5) in number tokens - isFunctionKeyword() was missing NTILE, FIRST_VALUE, LAST_VALUE, NTH_VALUE, PERCENT_RANK, CUME_DIST — they were parsed as column refs instead of functions - Window frame without AND (e.g. ROWS 5 PRECEDING) now defaults end to CURRENT ROW per SQL standard, instead of leaving it undefined
1 parent 5103d82 commit 1081f4a

2 files changed

Lines changed: 12 additions & 3 deletions

File tree

src/sql/lexer.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,18 @@ export function tokenize(sql: string): Token[] {
135135
continue;
136136
}
137137

138-
// Numbers
138+
// Numbers (supports decimals and scientific notation: 1e10, 1.5e-3, 3E+5)
139139
if (/[0-9]/.test(ch)) {
140140
while (pos < len && /[0-9]/.test(sql[pos])) pos++;
141141
if (pos < len && sql[pos] === ".") {
142142
pos++;
143143
while (pos < len && /[0-9]/.test(sql[pos])) pos++;
144144
}
145+
if (pos < len && (sql[pos] === "e" || sql[pos] === "E")) {
146+
pos++;
147+
if (pos < len && (sql[pos] === "+" || sql[pos] === "-")) pos++;
148+
while (pos < len && /[0-9]/.test(sql[pos])) pos++;
149+
}
145150
tokens.push({ type: TokenType.NUMBER, lexeme: sql.slice(start, pos), position: start });
146151
continue;
147152
}

src/sql/parser.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ class Parser {
734734
const frameType = this.match(TokenType.ROWS) ? "rows" as const : (this.advance(), "range" as const);
735735
this.match(TokenType.BETWEEN); // consume optional BETWEEN keyword
736736
const start = this.parseFrameBound();
737-
let end: NonNullable<SqlWindowSpec["frame"]>["end"];
737+
let end: NonNullable<SqlWindowSpec["frame"]>["end"] = { type: "current" as const };
738738
if (this.match(TokenType.AND)) {
739739
end = this.parseFrameBound();
740740
}
@@ -793,7 +793,11 @@ function isFunctionKeyword(type: TokenType): boolean {
793793
return type === TokenType.COUNT || type === TokenType.SUM ||
794794
type === TokenType.AVG || type === TokenType.MIN || type === TokenType.MAX ||
795795
type === TokenType.ROW_NUMBER || type === TokenType.RANK ||
796-
type === TokenType.DENSE_RANK || type === TokenType.LAG || type === TokenType.LEAD;
796+
type === TokenType.DENSE_RANK || type === TokenType.NTILE ||
797+
type === TokenType.LAG || type === TokenType.LEAD ||
798+
type === TokenType.FIRST_VALUE || type === TokenType.LAST_VALUE ||
799+
type === TokenType.NTH_VALUE || type === TokenType.PERCENT_RANK ||
800+
type === TokenType.CUME_DIST;
797801
}
798802

799803
function isKeywordIdentifier(type: TokenType): boolean {

0 commit comments

Comments
 (0)