@@ -237,7 +237,19 @@ pub fn translate_condition_expr(
237
237
resolver,
238
238
) ?;
239
239
}
240
- ast:: Expr :: Binary ( lhs, op, rhs) => {
240
+ ast:: Expr :: Binary ( lhs, op, rhs)
241
+ if matches ! (
242
+ op,
243
+ ast:: Operator :: Greater
244
+ | ast:: Operator :: GreaterEquals
245
+ | ast:: Operator :: Less
246
+ | ast:: Operator :: LessEquals
247
+ | ast:: Operator :: Equals
248
+ | ast:: Operator :: NotEquals
249
+ | ast:: Operator :: Is
250
+ | ast:: Operator :: IsNot
251
+ ) =>
252
+ {
241
253
let lhs_reg = program. alloc_register ( ) ;
242
254
let rhs_reg = program. alloc_register ( ) ;
243
255
translate_and_mark ( program, Some ( referenced_tables) , lhs, lhs_reg, resolver) ?;
@@ -267,35 +279,24 @@ pub fn translate_condition_expr(
267
279
ast:: Operator :: IsNot => {
268
280
emit_cmp_null_insn ! ( program, condition_metadata, Ne , Eq , lhs_reg, rhs_reg)
269
281
}
270
- _ => {
271
- todo ! ( "op {:?} not implemented" , op) ;
272
- }
282
+ _ => unreachable ! ( ) ,
273
283
}
274
284
}
275
- ast:: Expr :: Literal ( lit) => match lit {
276
- ast:: Literal :: Numeric ( val) => {
277
- let maybe_int = val. parse :: < i64 > ( ) ;
278
- if let Ok ( int_value) = maybe_int {
279
- let reg = program. alloc_register ( ) ;
280
- program. emit_insn ( Insn :: Integer {
281
- value : int_value,
282
- dest : reg,
283
- } ) ;
284
- emit_cond_jump ( program, condition_metadata, reg) ;
285
- } else {
286
- crate :: bail_parse_error!( "unsupported literal type in condition" ) ;
287
- }
288
- }
289
- ast:: Literal :: String ( string) => {
290
- let reg = program. alloc_register ( ) ;
291
- program. emit_insn ( Insn :: String8 {
292
- value : string. clone ( ) ,
293
- dest : reg,
294
- } ) ;
295
- emit_cond_jump ( program, condition_metadata, reg) ;
296
- }
297
- unimpl => todo ! ( "literal {:?} not implemented" , unimpl) ,
298
- } ,
285
+ ast:: Expr :: Binary ( _, _, _) => {
286
+ let result_reg = program. alloc_register ( ) ;
287
+ translate_expr ( program, Some ( referenced_tables) , expr, result_reg, resolver) ?;
288
+ emit_cond_jump ( program, condition_metadata, result_reg) ;
289
+ }
290
+ ast:: Expr :: Literal ( _)
291
+ | ast:: Expr :: Cast { .. }
292
+ | ast:: Expr :: FunctionCall { .. }
293
+ | ast:: Expr :: Column { .. }
294
+ | ast:: Expr :: RowId { .. }
295
+ | ast:: Expr :: Case { .. } => {
296
+ let reg = program. alloc_register ( ) ;
297
+ translate_expr ( program, Some ( referenced_tables) , expr, reg, resolver) ?;
298
+ emit_cond_jump ( program, condition_metadata, reg) ;
299
+ }
299
300
ast:: Expr :: InList { lhs, not, rhs } => {
300
301
// lhs is e.g. a column reference
301
302
// rhs is an Option<Vec<Expr>>
@@ -410,49 +411,9 @@ pub fn translate_condition_expr(
410
411
program. resolve_label ( jump_target_when_true, program. offset ( ) ) ;
411
412
}
412
413
}
413
- ast:: Expr :: Like {
414
- lhs,
415
- not,
416
- op,
417
- rhs,
418
- escape : _,
419
- } => {
414
+ ast:: Expr :: Like { not, .. } => {
420
415
let cur_reg = program. alloc_register ( ) ;
421
- match op {
422
- ast:: LikeOperator :: Like | ast:: LikeOperator :: Glob => {
423
- let start_reg = program. alloc_registers ( 2 ) ;
424
- let mut constant_mask = 0 ;
425
- translate_and_mark (
426
- program,
427
- Some ( referenced_tables) ,
428
- lhs,
429
- start_reg + 1 ,
430
- resolver,
431
- ) ?;
432
- let _ =
433
- translate_expr ( program, Some ( referenced_tables) , rhs, start_reg, resolver) ?;
434
- if matches ! ( rhs. as_ref( ) , ast:: Expr :: Literal ( _) ) {
435
- program. mark_last_insn_constant ( ) ;
436
- constant_mask = 1 ;
437
- }
438
- let func = match op {
439
- ast:: LikeOperator :: Like => ScalarFunc :: Like ,
440
- ast:: LikeOperator :: Glob => ScalarFunc :: Glob ,
441
- _ => unreachable ! ( ) ,
442
- } ;
443
- program. emit_insn ( Insn :: Function {
444
- constant_mask,
445
- start_reg,
446
- dest : cur_reg,
447
- func : FuncCtx {
448
- func : Func :: Scalar ( func) ,
449
- arg_count : 2 ,
450
- } ,
451
- } ) ;
452
- }
453
- ast:: LikeOperator :: Match => todo ! ( ) ,
454
- ast:: LikeOperator :: Regexp => todo ! ( ) ,
455
- }
416
+ translate_like_base ( program, Some ( referenced_tables) , expr, cur_reg, resolver) ?;
456
417
if !* not {
457
418
emit_cond_jump ( program, condition_metadata, cur_reg) ;
458
419
} else if condition_metadata. jump_if_condition_is_true {
@@ -500,7 +461,17 @@ pub fn translate_condition_expr(
500
461
target_pc : condition_metadata. jump_target_when_false ,
501
462
} ) ;
502
463
}
503
- _ => todo ! ( "op {:?} not implemented" , expr) ,
464
+ ast:: Expr :: Unary ( _, _) => {
465
+ // This is an inefficient implementation for op::NOT, because translate_expr() will emit an Insn::Not,
466
+ // and then we immediately emit an Insn::If/Insn::IfNot for the conditional jump. In reality we would not
467
+ // like to emit the negation instruction Insn::Not at all, since we could just emit the "opposite" jump instruction
468
+ // directly. However, using translate_expr() directly simplifies our conditional jump code for unary expressions,
469
+ // and we'd rather be correct than maximally efficient, for now.
470
+ let expr_reg = program. alloc_register ( ) ;
471
+ translate_expr ( program, Some ( referenced_tables) , expr, expr_reg, resolver) ?;
472
+ emit_cond_jump ( program, condition_metadata, expr_reg) ;
473
+ }
474
+ other => todo ! ( "expression {:?} not implemented" , other) ,
504
475
}
505
476
Ok ( ( ) )
506
477
}
@@ -1969,7 +1940,21 @@ pub fn translate_expr(
1969
1940
ast:: Expr :: InSelect { .. } => todo ! ( ) ,
1970
1941
ast:: Expr :: InTable { .. } => todo ! ( ) ,
1971
1942
ast:: Expr :: IsNull ( _) => todo ! ( ) ,
1972
- ast:: Expr :: Like { .. } => todo ! ( ) ,
1943
+ ast:: Expr :: Like { not, .. } => {
1944
+ let like_reg = if * not {
1945
+ program. alloc_register ( )
1946
+ } else {
1947
+ target_register
1948
+ } ;
1949
+ translate_like_base ( program, referenced_tables, expr, like_reg, resolver) ?;
1950
+ if * not {
1951
+ program. emit_insn ( Insn :: Not {
1952
+ reg : like_reg,
1953
+ dest : target_register,
1954
+ } ) ;
1955
+ }
1956
+ Ok ( target_register)
1957
+ }
1973
1958
ast:: Expr :: Literal ( lit) => match lit {
1974
1959
ast:: Literal :: Numeric ( val) => {
1975
1960
let maybe_int = val. parse :: < i64 > ( ) ;
@@ -2159,6 +2144,59 @@ pub fn translate_expr(
2159
2144
}
2160
2145
}
2161
2146
2147
+ /// The base logic for translating LIKE and GLOB expressions.
2148
+ /// The logic for handling "NOT LIKE" is different depending on whether the expression
2149
+ /// is a conditional jump or not. This is why the caller handles the "NOT LIKE" behavior;
2150
+ /// see [translate_condition_expr] and [translate_expr] for implementations.
2151
+ fn translate_like_base (
2152
+ program : & mut ProgramBuilder ,
2153
+ referenced_tables : Option < & [ TableReference ] > ,
2154
+ expr : & ast:: Expr ,
2155
+ target_register : usize ,
2156
+ resolver : & Resolver ,
2157
+ ) -> Result < usize > {
2158
+ let ast:: Expr :: Like {
2159
+ lhs,
2160
+ op,
2161
+ rhs,
2162
+ escape : _,
2163
+ ..
2164
+ } = expr
2165
+ else {
2166
+ crate :: bail_parse_error!( "expected Like expression" ) ;
2167
+ } ;
2168
+ match op {
2169
+ ast:: LikeOperator :: Like | ast:: LikeOperator :: Glob => {
2170
+ let start_reg = program. alloc_registers ( 2 ) ;
2171
+ let mut constant_mask = 0 ;
2172
+ translate_and_mark ( program, referenced_tables, lhs, start_reg + 1 , resolver) ?;
2173
+ let _ = translate_expr ( program, referenced_tables, rhs, start_reg, resolver) ?;
2174
+ if matches ! ( rhs. as_ref( ) , ast:: Expr :: Literal ( _) ) {
2175
+ program. mark_last_insn_constant ( ) ;
2176
+ constant_mask = 1 ;
2177
+ }
2178
+ let func = match op {
2179
+ ast:: LikeOperator :: Like => ScalarFunc :: Like ,
2180
+ ast:: LikeOperator :: Glob => ScalarFunc :: Glob ,
2181
+ _ => unreachable ! ( ) ,
2182
+ } ;
2183
+ program. emit_insn ( Insn :: Function {
2184
+ constant_mask,
2185
+ start_reg,
2186
+ dest : target_register,
2187
+ func : FuncCtx {
2188
+ func : Func :: Scalar ( func) ,
2189
+ arg_count : 2 ,
2190
+ } ,
2191
+ } ) ;
2192
+ }
2193
+ ast:: LikeOperator :: Match => todo ! ( ) ,
2194
+ ast:: LikeOperator :: Regexp => todo ! ( ) ,
2195
+ }
2196
+
2197
+ Ok ( target_register)
2198
+ }
2199
+
2162
2200
/// Emits a whole insn for a function call.
2163
2201
/// Assumes the number of parameters is valid for the given function.
2164
2202
/// Returns the target register for the function.
0 commit comments