@@ -25,10 +25,122 @@ pub trait SchemaView {
25
25
fn schema ( & self , name : & str , case_sensitive : bool ) -> Option < Arc < TableSchema > > ;
26
26
}
27
27
28
+ pub trait TypeChecker {
29
+ type Ast ;
30
+ type Set ;
31
+
32
+ fn type_ast ( ctx : & mut TyCtx , ast : Self :: Ast , tx : & impl SchemaView ) -> TypingResult < RelExpr > ;
33
+
34
+ fn type_set ( ctx : & mut TyCtx , ast : Self :: Set , tx : & impl SchemaView ) -> TypingResult < RelExpr > ;
35
+
36
+ fn type_from ( ctx : & mut TyCtx , from : SqlFrom < Self :: Ast > , tx : & impl SchemaView ) -> TypingResult < ( RelExpr , Vars ) > {
37
+ match from {
38
+ SqlFrom :: Expr ( expr, None ) => Self :: type_rel ( ctx, expr, tx) ,
39
+ SqlFrom :: Expr ( expr, Some ( alias) ) => {
40
+ let ( expr, _) = Self :: type_rel ( ctx, expr, tx) ?;
41
+ let ty = expr. ty_id ( ) ;
42
+ Ok ( ( expr, vec ! [ ( alias. name, ty) ] . into ( ) ) )
43
+ }
44
+ SqlFrom :: Join ( r, alias, joins) => {
45
+ let ( mut vars, mut args, mut exprs) = ( Vars :: default ( ) , Vec :: new ( ) , Vec :: new ( ) ) ;
46
+
47
+ let ( r, _) = Self :: type_rel ( ctx, r, tx) ?;
48
+ let ty = r. ty_id ( ) ;
49
+
50
+ args. push ( r) ;
51
+ vars. push ( ( alias. name , ty) ) ;
52
+
53
+ for join in joins {
54
+ let ( r, _) = Self :: type_rel ( ctx, join. expr , tx) ?;
55
+ let ty = r. ty_id ( ) ;
56
+
57
+ args. push ( r) ;
58
+ vars. push ( ( join. alias . name , ty) ) ;
59
+
60
+ if let Some ( on) = join. on {
61
+ exprs. push ( type_expr ( ctx, & vars, on, Some ( TyId :: BOOL ) ) ?) ;
62
+ }
63
+ }
64
+ let types = vars. iter ( ) . map ( |( _, ty) | * ty) . collect ( ) ;
65
+ let ty = Type :: Tup ( types) ;
66
+ let input = RelExpr :: Join ( args. into ( ) , ctx. add ( ty) ) ;
67
+ Ok ( ( RelExpr :: select ( input, vars. clone ( ) , exprs) , vars) )
68
+ }
69
+ }
70
+ }
71
+
72
+ fn type_rel ( ctx : & mut TyCtx , expr : ast:: RelExpr < Self :: Ast > , tx : & impl SchemaView ) -> TypingResult < ( RelExpr , Vars ) > {
73
+ match expr {
74
+ ast:: RelExpr :: Var ( var) => {
75
+ let schema = tx
76
+ . schema ( & var. name , var. case_sensitive )
77
+ . ok_or_else ( || Unresolved :: table ( & var. name ) )
78
+ . map_err ( TypingError :: from) ?;
79
+ let mut types = Vec :: new ( ) ;
80
+ for ColumnSchema { col_name, col_type, .. } in schema. columns ( ) {
81
+ let ty = Type :: Alg ( col_type. clone ( ) ) ;
82
+ let id = ctx. add ( ty) ;
83
+ types. push ( ( col_name. to_string ( ) , id) ) ;
84
+ }
85
+ let ty = Type :: Var ( types. into_boxed_slice ( ) ) ;
86
+ let id = ctx. add ( ty) ;
87
+ Ok ( ( RelExpr :: RelVar ( schema, id) , vec ! [ ( var. name, id) ] . into ( ) ) )
88
+ }
89
+ ast:: RelExpr :: Ast ( ast) => Ok ( ( Self :: type_ast ( ctx, * ast, tx) ?, Vars :: default ( ) ) ) ,
90
+ }
91
+ }
92
+ }
93
+
94
+ /// Type checker for subscriptions
95
+ struct SubChecker ;
96
+
97
+ impl TypeChecker for SubChecker {
98
+ type Ast = SqlAst ;
99
+ type Set = SqlAst ;
100
+
101
+ fn type_ast ( ctx : & mut TyCtx , ast : Self :: Ast , tx : & impl SchemaView ) -> TypingResult < RelExpr > {
102
+ Self :: type_set ( ctx, ast, tx)
103
+ }
104
+
105
+ fn type_set ( ctx : & mut TyCtx , ast : Self :: Set , tx : & impl SchemaView ) -> TypingResult < RelExpr > {
106
+ match ast {
107
+ SqlAst :: Union ( a, b) => {
108
+ let a = type_ast ( ctx, * a, tx) ?;
109
+ let b = type_ast ( ctx, * b, tx) ?;
110
+ assert_eq_types ( a. ty_id ( ) . try_with_ctx ( ctx) ?, b. ty_id ( ) . try_with_ctx ( ctx) ?) ?;
111
+ Ok ( RelExpr :: Union ( Box :: new ( a) , Box :: new ( b) ) )
112
+ }
113
+ SqlAst :: Minus ( a, b) => {
114
+ let a = type_ast ( ctx, * a, tx) ?;
115
+ let b = type_ast ( ctx, * b, tx) ?;
116
+ assert_eq_types ( a. ty_id ( ) . try_with_ctx ( ctx) ?, b. ty_id ( ) . try_with_ctx ( ctx) ?) ?;
117
+ Ok ( RelExpr :: Minus ( Box :: new ( a) , Box :: new ( b) ) )
118
+ }
119
+ SqlAst :: Select ( SqlSelect {
120
+ project,
121
+ from,
122
+ filter : None ,
123
+ } ) => {
124
+ let ( arg, vars) = type_from ( ctx, from, tx) ?;
125
+ type_proj ( ctx, project, arg, vars)
126
+ }
127
+ SqlAst :: Select ( SqlSelect {
128
+ project,
129
+ from,
130
+ filter : Some ( expr) ,
131
+ } ) => {
132
+ let ( from, vars) = type_from ( ctx, from, tx) ?;
133
+ let arg = type_select ( ctx, expr, from, vars. clone ( ) ) ?;
134
+ type_proj ( ctx, project, arg, vars. clone ( ) )
135
+ }
136
+ }
137
+ }
138
+ }
139
+
28
140
/// Parse and type check a subscription query
29
141
pub fn parse_and_type_sub ( sql : & str , tx : & impl SchemaView ) -> TypingResult < RelExpr > {
30
142
let mut ctx = TyCtx :: default ( ) ;
31
- let expr = type_ast ( & mut ctx, parse_subscription ( sql) ?, tx) ?;
143
+ let expr = SubChecker :: type_ast ( & mut ctx, parse_subscription ( sql) ?, tx) ?;
32
144
expect_table_type ( & ctx, expr)
33
145
}
34
146
@@ -128,13 +240,13 @@ fn type_rel(ctx: &mut TyCtx, expr: ast::RelExpr<SqlAst>, tx: &impl SchemaView) -
128
240
}
129
241
130
242
/// Type check and lower a [SqlExpr]
131
- fn type_select ( ctx : & mut TyCtx , expr : SqlExpr , input : RelExpr , vars : Vars ) -> TypingResult < RelExpr > {
243
+ pub ( crate ) fn type_select ( ctx : & mut TyCtx , expr : SqlExpr , input : RelExpr , vars : Vars ) -> TypingResult < RelExpr > {
132
244
let exprs = vec ! [ type_expr( ctx, & vars, expr, Some ( TyId :: BOOL ) ) ?] ;
133
245
Ok ( RelExpr :: select ( input, vars, exprs) )
134
246
}
135
247
136
248
/// Type check and lower a [ast::Project]
137
- fn type_proj ( ctx : & mut TyCtx , proj : ast:: Project , input : RelExpr , vars : Vars ) -> TypingResult < RelExpr > {
249
+ pub ( crate ) fn type_proj ( ctx : & mut TyCtx , proj : ast:: Project , input : RelExpr , vars : Vars ) -> TypingResult < RelExpr > {
138
250
match proj {
139
251
ast:: Project :: Star ( None ) => Ok ( input) ,
140
252
ast:: Project :: Star ( Some ( var) ) => {
@@ -167,7 +279,7 @@ fn type_proj(ctx: &mut TyCtx, proj: ast::Project, input: RelExpr, vars: Vars) ->
167
279
}
168
280
169
281
/// Type check and lower a [SqlExpr] into a logical [Expr].
170
- fn type_expr ( ctx : & TyCtx , vars : & Vars , expr : SqlExpr , expected : Option < TyId > ) -> TypingResult < Expr > {
282
+ pub ( crate ) fn type_expr ( ctx : & TyCtx , vars : & Vars , expr : SqlExpr , expected : Option < TyId > ) -> TypingResult < Expr > {
171
283
match ( expr, expected) {
172
284
( SqlExpr :: Lit ( SqlLiteral :: Bool ( v) ) , None | Some ( TyId :: BOOL ) ) => Ok ( Expr :: bool ( v) ) ,
173
285
( SqlExpr :: Lit ( SqlLiteral :: Bool ( _) ) , Some ( id) ) => {
@@ -195,7 +307,7 @@ fn type_expr(ctx: &TyCtx, vars: &Vars, expr: SqlExpr, expected: Option<TyId>) ->
195
307
}
196
308
197
309
/// Parses a source text literal as a particular type
198
- fn parse ( ctx : & TyCtx , v : String , id : TyId ) -> TypingResult < AlgebraicValue > {
310
+ pub ( crate ) fn parse ( ctx : & TyCtx , v : String , id : TyId ) -> TypingResult < AlgebraicValue > {
199
311
let err = |v, ty| TypingError :: from ( ConstraintViolation :: lit ( v, ty) ) ;
200
312
match ctx. try_resolve ( id) ? {
201
313
ty @ Type :: Alg ( AlgebraicType :: I8 ) => v
@@ -260,7 +372,7 @@ fn parse(ctx: &TyCtx, v: String, id: TyId) -> TypingResult<AlgebraicValue> {
260
372
}
261
373
262
374
/// Returns a type constraint violation for an unexpected type
263
- fn unexpected_type ( expected : TypeWithCtx < ' _ > , inferred : TypeWithCtx < ' _ > ) -> TypingError {
375
+ pub ( crate ) fn unexpected_type ( expected : TypeWithCtx < ' _ > , inferred : TypeWithCtx < ' _ > ) -> TypingError {
264
376
ConstraintViolation :: eq ( expected, inferred) . into ( )
265
377
}
266
378
@@ -282,7 +394,7 @@ fn expect_op_type(ctx: &TyCtx, op: BinOp, expr: Expr) -> TypingResult<Expr> {
282
394
}
283
395
}
284
396
285
- fn assert_eq_types ( a : TypeWithCtx < ' _ > , b : TypeWithCtx < ' _ > ) -> TypingResult < ( ) > {
397
+ pub ( crate ) fn assert_eq_types ( a : TypeWithCtx < ' _ > , b : TypeWithCtx < ' _ > ) -> TypingResult < ( ) > {
286
398
if a == b {
287
399
Ok ( ( ) )
288
400
} else {
0 commit comments