Skip to content

Commit 6c50bd9

Browse files
committed
expanded column expr to include *
1 parent b1a4981 commit 6c50bd9

File tree

10 files changed

+145
-59
lines changed

10 files changed

+145
-59
lines changed

Sources/Compiler/Parse/Parsers.swift

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,15 +1902,18 @@ enum Parsers {
19021902
while true {
19031903
// If the lhs was a column refernce with no table/schema and we are
19041904
// at an open paren treat as a function call.
1905-
if state.is(of: .openParen), case let .column(column) = expr, column.schema == nil {
1905+
if state.is(of: .openParen),
1906+
case let .column(columnExpr) = expr,
1907+
case let .column(column) = columnExpr.column,
1908+
columnExpr.schema == nil {
19061909
let args = try parensOrEmpty(state: &state) { state in
19071910
try commaDelimited(state: &state) { try Parsers.expr(state: &$0) }
19081911
}
19091912

19101913
expr = .fn(FunctionExprSyntax(
19111914
id: state.nextId(),
1912-
table: column.table,
1913-
name: column.column,
1915+
table: columnExpr.table,
1916+
name: column,
19141917
args: args ?? [],
19151918
location: state.location(from: expr.location))
19161919
)
@@ -1961,8 +1964,8 @@ enum Parsers {
19611964
switch state.current.kind {
19621965
case .double, .string, .int, .hex, .currentDate, .currentTime, .currentTimestamp, .true, .false:
19631966
return .literal(literal(state: &state))
1964-
case .symbol:
1965-
let column = columnExpr(state: &state)
1967+
case .symbol, .star:
1968+
let column = try columnExpr(state: &state, schema: nil, table: nil)
19661969
return .column(column)
19671970
case .questionMark, .colon, .dollarSign, .at:
19681971
return .bindParameter(bindParameter(state: &state))
@@ -2054,36 +2057,40 @@ enum Parsers {
20542057

20552058
return .infix(InfixExprSyntax(id: state.nextId(), lhs: lhs, operator: op, rhs: rhs))
20562059
}
2057-
2060+
20582061
/// https://www.sqlite.org/syntax/expr.html
2059-
static func columnExpr(state: inout ParserState) -> ColumnExprSyntax {
2060-
let first = identifier(state: &state)
2061-
2062-
if state.take(if: .dot) {
2063-
let second = identifier(state: &state)
2062+
static func columnExpr(
2063+
state: inout ParserState,
2064+
schema: IdentifierSyntax?,
2065+
table: IdentifierSyntax?
2066+
) throws -> ColumnExprSyntax {
2067+
switch state.current.kind {
2068+
case .star:
2069+
let star = state.take()
2070+
return ColumnExprSyntax(
2071+
id: state.nextId(),
2072+
schema: schema,
2073+
table: table,
2074+
column: .all(star.location)
2075+
)
2076+
case .symbol:
2077+
let ident = identifier(state: &state)
20642078

20652079
if state.take(if: .dot) {
2066-
return ColumnExprSyntax(
2067-
id: state.nextId(),
2068-
schema: first,
2069-
table: second,
2070-
column: identifier(state: &state)
2071-
)
2080+
return try columnExpr(state: &state, schema: table, table: ident)
20722081
} else {
20732082
return ColumnExprSyntax(
20742083
id: state.nextId(),
2075-
schema: nil,
2076-
table: first,
2077-
column: second
2084+
schema: schema,
2085+
table: table,
2086+
column: .column(ident)
20782087
)
20792088
}
2080-
} else {
2081-
return ColumnExprSyntax(
2082-
id: state.nextId(),
2083-
schema: nil,
2084-
table: nil,
2085-
column: first
2086-
)
2089+
default:
2090+
throw state.diagnostics.add(.init(
2091+
"Unexpected token, expected * or an identifier",
2092+
at: state.location
2093+
))
20872094
}
20882095
}
20892096

Sources/Compiler/Sema/CardinalityInferrer.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ extension CardinalityInferrer: ExprSyntaxVisitor {
151151
mutating func visit(_ expr: borrowing BindParameterSyntax) -> ExprOutput { [] }
152152

153153
mutating func visit(_ expr: borrowing ColumnExprSyntax) -> ExprOutput {
154-
return [expr.column.value]
154+
return switch expr.column {
155+
case .column(let column): [column.value]
156+
case .all: []
157+
}
155158
}
156159

157160
mutating func visit(_ expr: borrowing PrefixExprSyntax) -> ExprOutput {

Sources/Compiler/Sema/ExprTypeChecker.swift

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -99,33 +99,46 @@ extension ExprTypeChecker: ExprSyntaxVisitor {
9999
return inferenceState.errorType(for: expr)
100100
}
101101

102-
guard let type = columns[expr.column.value] else {
103-
diagnostics.add(.init(
104-
"Table '\(tableName)' has no column '\(expr.column)'",
105-
at: expr.location
106-
))
107-
return inferenceState.errorType(for: expr)
102+
let type: Type
103+
switch expr.column {
104+
case .column(let column):
105+
guard let t = columns[column.value] else {
106+
diagnostics.add(.init(
107+
"Table '\(tableName)' has no column '\(column)'",
108+
at: expr.location
109+
))
110+
return inferenceState.errorType(for: expr)
111+
}
112+
113+
type = t
114+
case .all:
115+
type = tableTy
108116
}
109117

110118
return (isOptional ? .optional(type) : type)
111119
} else {
112-
guard let result = env[expr.column.value] else {
113-
diagnostics.add(.init(
114-
"Column '\(expr.column)' does not exist",
115-
at: expr.location
116-
))
117-
return inferenceState.errorType(for: expr)
118-
}
119-
120-
// TODO: Maybe put this in the scheme instantiation?
121-
if result.isAmbiguous {
122-
diagnostics.add(.ambiguous(expr.column.value, at: expr.column.location))
120+
switch expr.column {
121+
case .column(let column):
122+
guard let result = env[column.value] else {
123+
diagnostics.add(.init(
124+
"Column '\(column)' does not exist",
125+
at: expr.location
126+
))
127+
return inferenceState.errorType(for: expr)
128+
}
129+
130+
// TODO: Maybe put this in the scheme instantiation?
131+
if result.isAmbiguous {
132+
diagnostics.add(.ambiguous(column.value, at: column.location))
133+
}
134+
135+
// Make sure to record the type in the inference state since
136+
// the type was pulled from the environment
137+
inferenceState.record(type: result.type, for: expr)
138+
return result.type
139+
case .all:
140+
return .row(.named(.init(uniqueKeysWithValues: env)))
123141
}
124-
125-
// Make sure to record the type in the inference state since
126-
// the type was pulled from the environment
127-
inferenceState.record(type: result.type, for: expr)
128-
return (result.type)
129142
}
130143
}
131144

Sources/Compiler/Sema/NameInferrer.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,12 @@ extension NameInferrer: ExprSyntaxVisitor {
229229
}
230230

231231
mutating func visit(_ expr: borrowing ColumnExprSyntax) -> Name {
232-
.some(expr.column.value)
232+
switch expr.column {
233+
case .column(let column):
234+
return .some(column.value)
235+
case .all:
236+
return .none
237+
}
233238
}
234239

235240
mutating func visit(_ expr: borrowing BindParameterSyntax) -> Name {

Sources/Compiler/Sema/StmtTypeChecker.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,6 @@ extension StmtTypeChecker: StmtSyntaxVisitor {
280280
}
281281

282282
if let when = stmt.when {
283-
insertTableAndColumnsIntoEnv(table)
284283
let (whenType, _) = typeCheck(when)
285284

286285
// Make sure the value is a valid boolean (integer)

Sources/Compiler/Syntax/Expressions/ColumnExprSyntax.swift

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,43 @@ struct ColumnExprSyntax: ExprSyntax, CustomStringConvertible {
99
let id: SyntaxId
1010
let schema: IdentifierSyntax?
1111
let table: IdentifierSyntax?
12-
let column: IdentifierSyntax // TODO: Support *
12+
let column: Column
13+
14+
enum Column: CustomStringConvertible {
15+
case column(IdentifierSyntax)
16+
case all(SourceLocation)
17+
18+
var description: String {
19+
return switch self {
20+
case .column(let c): c.description
21+
case .all: "*"
22+
}
23+
}
24+
25+
var location: SourceLocation {
26+
return switch self {
27+
case .column(let c): c.location
28+
case .all(let l): l
29+
}
30+
}
31+
}
1332

1433
var description: String {
15-
return [schema, table, column]
34+
let namespace = [schema, table]
1635
.compactMap { $0?.value }
1736
.joined(separator: ".")
37+
38+
return namespace.isEmpty ? column.description : "\(namespace).\(column)"
1839
}
1940

2041
var location: SourceLocation {
21-
let first = schema ?? table ?? column
22-
return first.location.spanning(column.location)
42+
let first = schema?.location ?? table?.location ?? column.location
43+
return first.spanning(column.location)
44+
}
45+
46+
var isSingleColumn: Bool {
47+
guard case .column = column else { return false }
48+
return true
2349
}
2450

2551
func accept<V: ExprSyntaxVisitor>(visitor: inout V) -> V.ExprOutput {

Sources/Compiler/Syntax/IndexedColumnSyntax.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ struct IndexedColumnSyntax: Syntax {
1717
}
1818

1919
var columnName: IdentifierSyntax? {
20-
guard case let .column(column) = expr else { return nil }
21-
return column.column
20+
guard case let .column(column) = expr,
21+
case let .column(name) = column.column else { return nil }
22+
return name
2223
}
2324
}

Tests/CompilerTests/Check/Check.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ struct CheckEmitter {
286286
is UInt, is UInt8, is UInt16, is UInt32, is UInt64,
287287
is Float, is Double, is String, is Any.Type, is IdentifierSyntax,
288288
is LiteralExprSyntax, is TableOptionsSyntax, is TypeNameSyntax, is BindParameterSyntax,
289-
is OperatorSyntax, is OrderSyntax, is Type, is AliasSyntax: true
289+
is OperatorSyntax, is OrderSyntax, is Type, is AliasSyntax, is ColumnExprSyntax.Column: true
290290
case _ as Substring:
291291
true
292292
default: false

Tests/CompilerTests/Compiler/CompileSimpleSelects.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,17 @@ FROM bar;
208208
-- CHECK: foo
209209
SELECT * FROM foo
210210
WHERE id IN (SELECT qux FROM bar WHERE qux > foo.id);
211+
212+
-- CHECK: SIGNATURE
213+
-- CHECK: OUTPUT_CHUNKS
214+
-- CHECK: CHUNK
215+
-- CHECK: OUTPUT
216+
-- CHECK: id INTEGER
217+
-- CHECK: bar (INTEGER AS Bool)?
218+
-- CHECK: baz TEXT
219+
-- CHECK: OUTPUT_TABLE foo
220+
-- CHECK: TABLES
221+
-- CHECK: bar
222+
-- CHECK: foo
223+
SELECT * FROM foo
224+
WHERE id > (SELECT COUNT(*) FROM bar);

Tests/CompilerTests/Parser/ParseExpression.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@ foo.bar;
1616
-- CHECK: COLUMN baz
1717
foo.bar.baz;
1818

19+
-- CHECK: EXPRESSION_SYNTAX
20+
-- CHECK: COLUMN
21+
-- CHECK: SCHEMA foo
22+
-- CHECK: TABLE bar
23+
-- CHECK: COLUMN *
24+
foo.bar.*;
25+
26+
-- CHECK: EXPRESSION_SYNTAX
27+
-- CHECK: COLUMN
28+
-- CHECK: TABLE bar
29+
-- CHECK: COLUMN *
30+
bar.*;
31+
32+
-- CHECK: EXPRESSION_SYNTAX
33+
-- CHECK: COLUMN
34+
-- CHECK: COLUMN *
35+
*;
36+
1937
-- CHECK: EXPRESSION_SYNTAX
2038
-- CHECK: LITERAL 1.0
2139
1.0;

0 commit comments

Comments
 (0)