Skip to content

Commit 6ed81dc

Browse files
committed
Fixed CTE’s not allowing multiple
1 parent e0df990 commit 6ed81dc

13 files changed

Lines changed: 114 additions & 146 deletions

Sources/Compiler/Parse/Parsers.swift

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -82,30 +82,15 @@ enum Parsers {
8282
return reindex(state: &state)
8383
case (.with, _):
8484
let start = state.current
85-
let cte = try withCte(state: &state)
85+
let with = try take(if: .with, state: &state, parse: with)
8686

8787
switch state.current.kind {
8888
case .select:
89-
return try selectStmt(
90-
state: &state,
91-
start: start,
92-
cteRecursive: cte.recursive,
93-
cte: cte.cte
94-
)
89+
return try selectStmt(state: &state, start: start, with: with)
9590
case .insert:
96-
return try insertStmt(
97-
state: &state,
98-
start: start,
99-
cteRecursive: cte.recursive,
100-
cte: cte.cte
101-
)
91+
return try insertStmt(state: &state, start: start, with: with)
10292
case .delete:
103-
return try deleteStmt(
104-
state: &state,
105-
start: start,
106-
cteRecursive: cte.recursive,
107-
cte: cte.cte
108-
)
93+
return try deleteStmt(state: &state, start: start, with: with)
10994
default:
11095
state.diagnostics.add(.unexpectedToken(of: state.current.kind, at: state.location))
11196
return EmptyStmtSyntax(id: state.nextId(), location: state.current.location)
@@ -121,21 +106,19 @@ enum Parsers {
121106

122107
static func insertStmt(state: inout ParserState) throws -> InsertStmtSyntax {
123108
let start = state.current
124-
let cte = try withCte(state: &state)
109+
let with = try take(if: .with, state: &state, parse: with)
125110
return try insertStmt(
126111
state: &state,
127112
start: start,
128-
cteRecursive: cte.recursive,
129-
cte: cte.cte
113+
with: with
130114
)
131115
}
132116

133117
/// https://www.sqlite.org/lang_insert.html
134118
static func insertStmt(
135119
state: inout ParserState,
136120
start: Token,
137-
cteRecursive: Bool,
138-
cte: CommonTableExpressionSyntax?
121+
with: WithSyntax?
139122
) throws -> InsertStmtSyntax {
140123
let action = insertAction(state: &state)
141124
state.consume(.into)
@@ -147,8 +130,7 @@ enum Parsers {
147130

148131
return InsertStmtSyntax(
149132
id: state.nextId(),
150-
cte: cte,
151-
cteRecursive: cteRecursive,
133+
with: with,
152134
action: action,
153135
tableName: tableName,
154136
tableAlias: alias,
@@ -507,7 +489,7 @@ enum Parsers {
507489
/// https://www.sqlite.org/lang_update.html
508490
static func updateStmt(state: inout ParserState) throws -> UpdateStmtSyntax {
509491
let start = state.location
510-
let cte = try withCte(state: &state)
492+
let with = try take(if: .with, state: &state, parse: with)
511493
state.consume(.update)
512494
let or = take(if: .or, state: &state, parse: or)
513495
let tableName = qualifiedTableName(state: &state)
@@ -521,8 +503,7 @@ enum Parsers {
521503
let returningClause = try take(if: .returning, state: &state, parse: returningClause)
522504
return UpdateStmtSyntax(
523505
id: state.nextId(),
524-
cte: cte.cte,
525-
cteRecursive: cte.recursive,
506+
with: with,
526507
or: or,
527508
tableName: tableName,
528509
sets: sets,
@@ -536,21 +517,19 @@ enum Parsers {
536517
/// https://www.sqlite.org/lang_delete.html
537518
static func deleteStmt(state: inout ParserState) throws -> DeleteStmtSyntax {
538519
let start = state.current
539-
let cte = try withCte(state: &state)
520+
let with = try take(if: .with, state: &state, parse: with)
540521
return try deleteStmt(
541522
state: &state,
542523
start: start,
543-
cteRecursive: cte.recursive,
544-
cte: cte.cte
524+
with: with
545525
)
546526
}
547527

548528
/// https://www.sqlite.org/lang_delete.html
549529
static func deleteStmt(
550530
state: inout ParserState,
551531
start: Token,
552-
cteRecursive: Bool,
553-
cte: CommonTableExpressionSyntax?
532+
with: WithSyntax?
554533
) throws -> DeleteStmtSyntax {
555534
state.consume(.delete)
556535
state.consume(.from)
@@ -559,8 +538,7 @@ enum Parsers {
559538
let returningClause = try state.current.kind == .returning ? returningClause(state: &state) : nil
560539
return DeleteStmtSyntax(
561540
id: state.nextId(),
562-
cte: cte,
563-
cteRecursive: cteRecursive,
541+
with: with,
564542
table: table,
565543
whereExpr: whereExpr,
566544
returningClause: returningClause,
@@ -617,15 +595,17 @@ enum Parsers {
617595
}
618596

619597
/// https://www.sqlite.org/lang_with.html
620-
static func withCte(
621-
state: inout ParserState
622-
) throws -> (cte: CommonTableExpressionSyntax?, recursive: Bool) {
623-
if state.take(if: .with) {
624-
let cteRecursive = state.take(if: .recursive)
625-
return try (cte(state: &state), cteRecursive)
626-
} else {
627-
return (nil, false)
628-
}
598+
static func with(state: inout ParserState) throws -> WithSyntax {
599+
let with = state.take(.with)
600+
let recursive = state.take(if: .recursive)
601+
let ctes = try commaDelimited(state: &state, element: cte)
602+
603+
return WithSyntax(
604+
id: state.nextId(),
605+
location: state.location(from: with),
606+
recursive: recursive,
607+
ctes: ctes
608+
)
629609
}
630610

631611
/// https://www.sqlite.org/syntax/common-table-expression.html
@@ -795,25 +775,23 @@ enum Parsers {
795775
/// https://www.sqlite.org/syntax/select-stmt.html
796776
static func selectStmt(state: inout ParserState) throws -> SelectStmtSyntax {
797777
let start = state.current
798-
let cte = try withCte(state: &state)
799-
return try selectStmt(state: &state, start: start, cteRecursive: cte.recursive, cte: cte.cte)
778+
let with = try take(if: .with, state: &state, parse: with)
779+
return try selectStmt(state: &state, start: start, with: with)
800780
}
801781

802782
/// https://www.sqlite.org/syntax/select-stmt.html
803783
static func selectStmt(
804784
state: inout ParserState,
805785
start: Token,
806-
cteRecursive: Bool,
807-
cte: CommonTableExpressionSyntax?
786+
with: WithSyntax?
808787
) throws -> SelectStmtSyntax {
809788
let selects = try selects(state: &state)
810789
let orderBy = try orderingTerms(state: &state)
811790
let limit = try limit(state: &state)
812791

813792
return SelectStmtSyntax(
814793
id: state.nextId(),
815-
cte: cte.map(Indirect.init),
816-
cteRecursive: cteRecursive,
794+
with: with,
817795
selects: .init(selects),
818796
orderBy: orderBy,
819797
limit: limit,

Sources/Compiler/Sema/NameInferrer.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,10 @@ struct NameInferrer {
8383
}
8484

8585
private mutating func infer(select: SelectStmtSyntax) {
86-
if let cte = select.cte {
87-
infer(select: cte.select)
86+
if let with = select.with {
87+
for cte in with.ctes {
88+
infer(select: cte.select)
89+
}
8890
}
8991

9092
infer(selects: select.selects.value)

Sources/Compiler/Sema/StmtTypeChecker.swift

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -339,13 +339,7 @@ extension StmtTypeChecker {
339339
select: SelectStmtSyntax,
340340
potentialNames: [IdentifierSyntax]? = nil
341341
) -> ResultColumns {
342-
if let cte = select.cte?.value {
343-
let cte = inNewEnvironment { typeChecker in
344-
typeChecker.typeCheck(cte: cte)
345-
}
346-
347-
ctes[cte.name] = cte
348-
}
342+
typeCheck(with: select.with)
349343

350344
// Type check limit before since it does not have access
351345
// to any selected columns
@@ -431,13 +425,7 @@ extension StmtTypeChecker {
431425
}
432426

433427
mutating func typeCheck(insert: InsertStmtSyntax) -> ResultColumns {
434-
if let cte = insert.cte {
435-
let cte = inNewEnvironment { typeChecker in
436-
typeChecker.typeCheck(cte: cte)
437-
}
438-
439-
ctes[cte.name] = cte
440-
}
428+
typeCheck(with: insert.with)
441429

442430
guard let table = schema[insert.tableName.name.value] else {
443431
diagnostics.add(.tableDoesNotExist(insert.tableName.name))
@@ -481,13 +469,7 @@ extension StmtTypeChecker {
481469
}
482470

483471
mutating func typeCheck(update: UpdateStmtSyntax) -> ResultColumns {
484-
if let cte = update.cte {
485-
let cte = inNewEnvironment { typeChecker in
486-
typeChecker.typeCheck(cte: cte)
487-
}
488-
489-
ctes[cte.name] = cte
490-
}
472+
typeCheck(with: update.with)
491473

492474
guard let table = schema[update.tableName.tableName.name.value] else {
493475
diagnostics.add(.tableDoesNotExist(update.tableName.tableName.name))
@@ -537,13 +519,7 @@ extension StmtTypeChecker {
537519
}
538520

539521
mutating func typeCheck(delete: DeleteStmtSyntax) -> ResultColumns {
540-
if let cte = delete.cte {
541-
let cte = inNewEnvironment { typeChecker in
542-
typeChecker.typeCheck(cte: cte)
543-
}
544-
545-
ctes[cte.name] = cte
546-
}
522+
typeCheck(with: delete.with)
547523

548524
guard let table = schema[delete.table.tableName.name.value] else {
549525
diagnostics.add(.tableDoesNotExist(delete.table.tableName.name))
@@ -606,6 +582,18 @@ extension StmtTypeChecker {
606582
return ResultColumns(columns: resultColumns, table: nil)
607583
}
608584

585+
private mutating func typeCheck(with: WithSyntax?) {
586+
guard let with else { return }
587+
588+
for cte in with.ctes {
589+
let table = inNewEnvironment { typeChecker in
590+
typeChecker.typeCheck(cte: cte)
591+
}
592+
593+
ctes[cte.table.value] = table
594+
}
595+
}
596+
609597
private mutating func typeCheck(cte: CommonTableExpressionSyntax) -> Table {
610598
let resultColumns = typeCheck(select: cte.select)
611599

Sources/Compiler/Syntax/Statements/DeleteStmtSyntax.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88
struct DeleteStmtSyntax: StmtSyntax {
99
let id: SyntaxId
10-
let cte: CommonTableExpressionSyntax?
11-
let cteRecursive: Bool
10+
let with: WithSyntax?
1211
let table: QualifiedTableNameSyntax
1312
let whereExpr: ExpressionSyntax?
1413
let returningClause: ReturningClauseSyntax?

Sources/Compiler/Syntax/Statements/InsertStmtSyntax.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88
struct InsertStmtSyntax: StmtSyntax, Syntax {
99
let id: SyntaxId
10-
let cte: CommonTableExpressionSyntax?
11-
let cteRecursive: Bool
10+
let with: WithSyntax?
1211
let action: Action
1312
let tableName: TableNameSyntax
1413
let tableAlias: AliasSyntax?

Sources/Compiler/Syntax/Statements/SelectStmtSyntax.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88
struct SelectStmtSyntax: StmtSyntax {
99
let id: SyntaxId
10-
let cte: Indirect<CommonTableExpressionSyntax>?
11-
let cteRecursive: Bool
10+
let with: WithSyntax?
1211
let selects: Indirect<Selects>
1312
let orderBy: [OrderingTermSyntax]
1413
let limit: Limit?

Sources/Compiler/Syntax/Statements/UpdateStmtSyntax.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88
struct UpdateStmtSyntax: StmtSyntax {
99
let id: SyntaxId
10-
let cte: CommonTableExpressionSyntax?
11-
let cteRecursive: Bool
10+
let with: WithSyntax?
1211
let or: OrSyntax?
1312
let tableName: QualifiedTableNameSyntax
1413
let sets: [SetActionSyntax]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//
2+
// WithSyntax.swift
3+
// Feather
4+
//
5+
// Created by Wes Wickwire on 5/20/25.
6+
//
7+
8+
struct WithSyntax: Syntax {
9+
let id: SyntaxId
10+
let location: SourceLocation
11+
let recursive: Bool
12+
let ctes: [CommonTableExpressionSyntax]
13+
}

Tests/CompilerTests/Parser/ParseCommonTableExpression.sql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
-- CHECK: name
66
-- CHECK: MATERIALIZED false
77
-- CHECK: SELECT
8-
-- CHECK: CTE_RECURSIVE false
98
-- CHECK: SELECTS
109
-- CHECK: VALUE
1110
-- CHECK: SINGLE

Tests/CompilerTests/Parser/ParseDeleteStmt.sql

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
-- CHECK: DELETE_STMT_SYNTAX
2-
-- CHECK: CTE_RECURSIVE false
32
-- CHECK: TABLE
43
-- CHECK: TABLE_NAME
54
-- CHECK: SCHEMA main
65
-- CHECK: NAME user
76
DELETE FROM user;
87

98
-- CHECK: DELETE_STMT_SYNTAX
10-
-- CHECK: CTE_RECURSIVE false
119
-- CHECK: TABLE
1210
-- CHECK: TABLE_NAME
1311
-- CHECK: SCHEMA main
@@ -23,7 +21,6 @@ DELETE FROM user;
2321
DELETE FROM user WHERE id = ?;
2422

2523
-- CHECK: DELETE_STMT_SYNTAX
26-
-- CHECK: CTE_RECURSIVE false
2724
-- CHECK: TABLE
2825
-- CHECK: TABLE_NAME
2926
-- CHECK: SCHEMA main

0 commit comments

Comments
 (0)