rustdb/
compile.rs

1use crate::*;
2use std::{mem, ops};
3use Instruction::*;
4
5/// Calculate various attributes such as data_type, is_constant etc.
6pub fn c_check(b: &Block, e: &mut Expr) {
7    if e.checked {
8        return;
9    }
10    e.is_constant = true;
11    match &mut e.exp {
12        ExprIs::BuiltinCall(name, args) => {
13            if let Some((dk, _cf)) = b.db.builtins.get(name) {
14                e.data_type = *dk as DataType;
15                for pe in args {
16                    c_check(b, pe);
17                    if !pe.is_constant {
18                        e.is_constant = false;
19                    }
20                }
21            } else {
22                panic!("unknown function {}", name);
23            }
24        }
25        ExprIs::Binary(op, b1, b2) => {
26            c_check(b, b1);
27            c_check(b, b2);
28            e.is_constant = b1.is_constant && b2.is_constant;
29            let t1 = b1.data_type;
30            let t2 = b2.data_type;
31            if data_kind(t1) != data_kind(t2) && *op != Token::VBar {
32                panic!("binary op type mismatch")
33            }
34            e.data_type = match op {
35                Token::Less
36                | Token::LessEqual
37                | Token::GreaterEqual
38                | Token::Greater
39                | Token::Equal
40                | Token::NotEqual => BOOL,
41                Token::And | Token::Or => {
42                    if t1 != BOOL {
43                        panic!("AND/OR need bool operands")
44                    }
45                    BOOL
46                }
47                Token::Plus | Token::Times | Token::Minus | Token::Divide | Token::Percent => t1,
48                Token::VBar => {
49                    if data_kind(t1) == DataKind::Binary {
50                        BINARY
51                    } else {
52                        STRING
53                    }
54                }
55                _ => panic!(),
56            }
57        }
58        ExprIs::Local(x) => {
59            e.data_type = b.local_typ[*x];
60        }
61        ExprIs::Const(x) => {
62            e.data_type = match *x {
63                Value::Bool(_) => BOOL,
64                Value::Int(_) => INT,
65                Value::Float(_) => DOUBLE,
66                Value::String(_) => STRING,
67                Value::RcBinary(_) => BINARY,
68                Value::ArcBinary(_) => BINARY,
69                _ => NONE,
70            }
71        }
72        ExprIs::Case(x, els) => {
73            c_check(b, els);
74            if !els.is_constant {
75                e.is_constant = false;
76            }
77            e.data_type = els.data_type;
78            for (w, t) in x {
79                c_check(b, w);
80                if !w.is_constant {
81                    e.is_constant = false;
82                }
83                c_check(b, t);
84                if !t.is_constant {
85                    e.is_constant = false;
86                }
87                if data_kind(e.data_type) != data_kind(t.data_type) {
88                    panic!("CASE branch type mismatch");
89                }
90            }
91        }
92        ExprIs::Not(x) => {
93            c_check(b, x);
94            e.is_constant = x.is_constant;
95            e.data_type = BOOL;
96        }
97        ExprIs::Minus(x) => {
98            c_check(b, x);
99            e.is_constant = x.is_constant;
100            e.data_type = x.data_type;
101        }
102        ExprIs::FuncCall(name, parms) => {
103            let f = c_function(&b.db, name);
104            e.data_type = f.return_type;
105            if parms.len() != f.param_count {
106                panic!(
107                    "function parameter count mismatch expected {} got {}",
108                    f.param_count,
109                    parms.len()
110                );
111            }
112            for (i, a) in parms.iter_mut().enumerate() {
113                c_check(b, a);
114                let (t, et) = (data_kind(a.data_type), data_kind(f.local_typ[i]));
115                if t != et {
116                    panic!("function param type mismatch expected {:?} got {:?}", et, t);
117                }
118                if !a.is_constant {
119                    e.is_constant = false;
120                }
121            }
122        }
123        ExprIs::ColName(x) => {
124            e.is_constant = false;
125            let (col, data_type) = name_to_colnum(b, x);
126            e.col = col;
127            e.data_type = data_type;
128        }
129        _ => panic!(),
130    }
131    e.checked = true;
132}
133
134/// Compile a call to a builtin function that returns a Value.
135fn c_builtin_value(b: &Block, name: &str, args: &mut [Expr]) -> CExpPtr<Value> {
136    if let Some((_dk, CompileFunc::Value(cf))) = b.db.builtins.get(name) {
137        return cf(b, args);
138    }
139    panic!()
140}
141
142/// Compile an expression.
143pub fn c_value(b: &Block, e: &mut Expr) -> CExpPtr<Value> {
144    match b.kind(e) {
145        DataKind::Bool => Box::new(cexp::BoolToVal(c_bool(b, e))),
146        DataKind::Int => Box::new(cexp::IntToVal(c_int(b, e))),
147        DataKind::Float => Box::new(cexp::FloatToVal(c_float(b, e))),
148        _ => match &mut e.exp {
149            ExprIs::ColName(x) => {
150                let (off, typ) = name_to_col(b, x);
151                let size = data_size(typ);
152                match data_kind(typ) {
153                    DataKind::String => Box::new(cexp::ColumnString { off, size }),
154                    DataKind::Binary => Box::new(cexp::ColumnBinary { off, size }),
155                    _ => panic!(),
156                }
157            }
158            ExprIs::Const(x) => Box::new(cexp::Const((*x).clone())),
159            ExprIs::Local(x) => Box::new(cexp::Local(*x)),
160            ExprIs::Binary(op, b1, b2) => {
161                let c1 = c_value(b, b1);
162                let c2 = c_value(b, b2);
163                match op {
164                    Token::VBar => {
165                        if data_kind(b1.data_type) == DataKind::Binary {
166                            Box::new(cexp::BinConcat(c1, c2))
167                        } else {
168                            Box::new(cexp::Concat(c1, c2))
169                        }
170                    }
171                    _ => panic!("invalid operator {:?}", op),
172                }
173            }
174            ExprIs::FuncCall(name, parms) => c_call(b, name, parms),
175            ExprIs::Case(list, els) => c_case(b, list, els, c_value),
176            ExprIs::BuiltinCall(name, parms) => c_builtin_value(b, name, parms),
177            _ => panic!(),
178        },
179    }
180}
181
182/// Compile int expression.
183pub fn c_int(b: &Block, e: &mut Expr) -> CExpPtr<i64> {
184    if b.kind(e) != DataKind::Int {
185        panic!("int type expected")
186    }
187    match &mut e.exp {
188        ExprIs::ColName(x) => {
189            let (off, typ) = name_to_col(b, x);
190            let size = data_size(typ);
191            match size {
192                8 => Box::new(cexp::ColumnI64 { off }),
193                1 => Box::new(cexp::ColumnI8 { off }),
194                _ => Box::new(cexp::ColumnI { off, size }),
195            }
196        }
197        ExprIs::Const(Value::Int(b)) => Box::new(cexp::Const::<i64>(*b)),
198        ExprIs::Local(num) => Box::new(cexp::Local(*num)),
199        ExprIs::Binary(op, b1, b2) => c_arithmetic(b, *op, b1, b2, c_int),
200        ExprIs::Minus(x) => Box::new(cexp::Minus::<i64>(c_int(b, x))),
201        ExprIs::Case(w, e) => c_case(b, w, e, c_int),
202        ExprIs::FuncCall(n, a) => Box::new(cexp::ValToInt(c_call(b, n, a))),
203        ExprIs::BuiltinCall(n, a) => c_builtin_int(b, n, a),
204        _ => panic!(),
205    }
206}
207
208/// Compile float expression.
209pub fn c_float(b: &Block, e: &mut Expr) -> CExpPtr<f64> {
210    if b.kind(e) != DataKind::Float {
211        panic!("float type expected")
212    }
213    match &mut e.exp {
214        ExprIs::ColName(x) => {
215            let (off, typ) = name_to_col(b, x);
216            match data_size(typ) {
217                8 => Box::new(cexp::ColumnF64 { off }),
218                4 => Box::new(cexp::ColumnF32 { off }),
219                _ => panic!(),
220            }
221        }
222        ExprIs::Local(num) => Box::new(cexp::Local(*num)),
223        ExprIs::Binary(op, b1, b2) => c_arithmetic(b, *op, b1, b2, c_float),
224        ExprIs::Minus(x) => Box::new(cexp::Minus::<f64>(c_float(b, x))),
225        ExprIs::Case(w, e) => c_case(b, w, e, c_float),
226        ExprIs::FuncCall(n, a) => Box::new(cexp::ValToFloat(c_call(b, n, a))),
227        ExprIs::BuiltinCall(n, a) => c_builtin_float(b, n, a),
228        _ => panic!(),
229    }
230}
231
232/// Compile bool expression.
233pub fn c_bool(b: &Block, e: &mut Expr) -> CExpPtr<bool> {
234    if b.kind(e) != DataKind::Bool {
235        panic!("bool type expected")
236    }
237    match &mut e.exp {
238        ExprIs::ColName(x) => {
239            let (off, _typ) = name_to_col(b, x);
240            Box::new(cexp::ColumnBool { off })
241        }
242        ExprIs::Const(Value::Bool(b)) => Box::new(cexp::Const::<bool>(*b)),
243        ExprIs::Local(x) => Box::new(cexp::Local(*x)),
244        ExprIs::Binary(op, b1, b2) => {
245            if *op == Token::Or || *op == Token::And {
246                let c1 = c_bool(b, b1);
247                let c2 = c_bool(b, b2);
248                match op {
249                    Token::Or => Box::new(cexp::Or(c1, c2)),
250                    Token::And => Box::new(cexp::And(c1, c2)),
251                    _ => panic!(),
252                }
253            } else {
254                match b.kind(b1) {
255                    DataKind::Bool => c_compare(b, *op, b1, b2, c_bool),
256                    DataKind::Int => c_compare(b, *op, b1, b2, c_int),
257                    DataKind::Float => c_compare(b, *op, b1, b2, c_float),
258                    _ => c_compare(b, *op, b1, b2, c_value),
259                }
260            }
261        }
262        ExprIs::Not(x) => Box::new(cexp::Not(c_bool(b, x))),
263        ExprIs::FuncCall(name, parms) => Box::new(cexp::ValToBool(c_call(b, name, parms))),
264        ExprIs::Case(list, els) => c_case(b, list, els, c_bool),
265        _ => panic!(),
266    }
267}
268
269/// Compile arithmetic.
270fn c_arithmetic<T>(
271    b: &Block,
272    op: Token,
273    e1: &mut Expr,
274    e2: &mut Expr,
275    cexp: fn(&Block, &mut Expr) -> CExpPtr<T>,
276) -> CExpPtr<T>
277where
278    T: 'static
279        + ops::Add<Output = T>
280        + ops::Sub<Output = T>
281        + ops::Mul<Output = T>
282        + ops::Div<Output = T>
283        + ops::Rem<Output = T>,
284{
285    let c1 = cexp(b, e1);
286    let c2 = cexp(b, e2);
287    match op {
288        Token::Plus => Box::new(cexp::Add::<T>(c1, c2)),
289        Token::Minus => Box::new(cexp::Sub::<T>(c1, c2)),
290        Token::Times => Box::new(cexp::Mul::<T>(c1, c2)),
291        Token::Divide => Box::new(cexp::Div::<T>(c1, c2)),
292        Token::Percent => Box::new(cexp::Rem::<T>(c1, c2)),
293        _ => panic!(),
294    }
295}
296
297/// Compile comparison.
298fn c_compare<T>(
299    b: &Block,
300    op: Token,
301    e1: &mut Expr,
302    e2: &mut Expr,
303    cexp: fn(&Block, &mut Expr) -> CExpPtr<T>,
304) -> CExpPtr<bool>
305where
306    T: 'static + std::cmp::PartialOrd,
307{
308    let c1 = cexp(b, e1);
309    let c2 = cexp(b, e2);
310    match op {
311        Token::Equal => Box::new(cexp::Equal::<T>(c1, c2)),
312        Token::NotEqual => Box::new(cexp::NotEqual::<T>(c1, c2)),
313        Token::Less => Box::new(cexp::Less::<T>(c1, c2)),
314        Token::Greater => Box::new(cexp::Greater::<T>(c1, c2)),
315        Token::LessEqual => Box::new(cexp::LessEqual::<T>(c1, c2)),
316        Token::GreaterEqual => Box::new(cexp::GreaterEqual::<T>(c1, c2)),
317        _ => panic!(),
318    }
319}
320
321/// Compile CASE Expression.
322fn c_case<T>(
323    b: &Block,
324    wes: &mut [(Expr, Expr)],
325    els: &mut Expr,
326    cexp: fn(&Block, &mut Expr) -> CExpPtr<T>,
327) -> CExpPtr<T>
328where
329    T: 'static,
330{
331    let mut whens = Vec::new();
332    for (be, ve) in wes {
333        let cb = c_bool(b, be);
334        let v = cexp(b, ve);
335        whens.push((cb, v));
336    }
337    let els = cexp(b, els);
338    Box::new(cexp::Case::<T> { whens, els })
339}
340
341/// Compile a call to a builtin function that returns an integer.
342fn c_builtin_int(b: &Block, name: &str, args: &mut [Expr]) -> CExpPtr<i64> {
343    if let Some((_dk, CompileFunc::Int(cf))) = b.db.builtins.get(name) {
344        return cf(b, args);
345    }
346    panic!()
347}
348
349/// Compile a call to a builtin function that returns a float.
350fn c_builtin_float(b: &Block, name: &str, args: &mut [Expr]) -> CExpPtr<f64> {
351    if let Some((_dk, CompileFunc::Float(cf))) = b.db.builtins.get(name) {
352        return cf(b, args);
353    }
354    panic!()
355}
356
357/// Compile UPDATE statement.
358pub fn c_update(
359    b: &mut Block,
360    tname: &ObjRef,
361    assigns: &mut [(String, Expr)],
362    wher: &mut Option<Expr>,
363) {
364    let t = c_table(b, tname);
365    let from = CTableExpression::Base(t.clone());
366    let save = mem::replace(&mut b.from, Some(from));
367    let mut se = Vec::new();
368    for (name, exp) in assigns.iter_mut() {
369        if let Some(cnum) = t.info.colmap.get(name) {
370            let exp = c_value(b, exp);
371            se.push((*cnum, exp));
372        } else {
373            panic!("update column name not found");
374        }
375    }
376    let (w, index_from) = c_where(b, Some(t), wher);
377    let mut from = mem::replace(&mut b.from, save);
378    if index_from.is_some() {
379        from = index_from;
380    }
381    b.dop(DO::Update(se, from.unwrap(), w));
382}
383
384/// Compile DELETE statement.
385pub fn c_delete(b: &mut Block, tname: &ObjRef, wher: &mut Option<Expr>) {
386    let t = c_table(b, tname);
387    let from = Some(CTableExpression::Base(t.clone()));
388    let save = mem::replace(&mut b.from, from);
389    let (w, index_from) = c_where(b, Some(t), wher);
390    let mut from = mem::replace(&mut b.from, save);
391    if index_from.is_some() {
392        from = index_from;
393    }
394    b.dop(DO::Delete(from.unwrap(), w));
395}
396
397/// Compile FromExpression in Set context.
398pub fn c_set(b: &mut Block, mut se: FromExpression) {
399    if se.from.is_none() {
400        // Optimise assigns by generating specific instructions.
401        for (i, e) in se.exps.iter_mut().enumerate() {
402            // Check data kind of assigned local matches data kind of expression.
403            let (lnum, op) = se.assigns[i];
404            let ek = data_kind(b.local_typ[lnum]);
405            let ce = c_value(b, e);
406            let ak = b.kind(e);
407            if ek != ak {
408                panic!("cannot assign {:?} to {:?}", ak, ek);
409            }
410            match op {
411                AssignOp::Assign => b.add(AssignLocal(lnum, ce)),
412                AssignOp::Append => b.add(AppendLocal(lnum, ce)),
413                AssignOp::Inc => b.add(IncLocal(lnum, ce)),
414                AssignOp::Dec => b.add(DecLocal(lnum, ce)),
415            }
416        }
417    } else {
418        let cte = c_select(b, se);
419        b.add(Set(Box::new(cte)));
420    }
421}
422
423/// Compile FromExpression to CFromExpression.
424pub fn c_select(b: &mut Block, mut x: FromExpression) -> CFromExpression {
425    let mut from = x.from.map(|mut te| c_te(b, &mut te));
426    let table = match &from {
427        Some(CTableExpression::Base(t)) => Some(t.clone()),
428        _ => None,
429    };
430    // Is the save necessary?
431    let save = mem::replace(&mut b.from, from);
432    let mut exps = Vec::new();
433    for (i, e) in x.exps.iter_mut().enumerate() {
434        exps.push(c_value(b, e));
435        if !x.assigns.is_empty() {
436            // Check data kind of assigned local matches data kind of expression.
437            let (lnum, _) = x.assigns[i];
438            let ek = data_kind(b.local_typ[lnum]);
439            let ak = data_kind(e.data_type);
440            if ek != ak {
441                panic!("cannot assign {:?} to {:?}", ak, ek);
442            }
443        }
444    }
445    let (wher, index_from) = c_where(b, table, &mut x.wher);
446    let mut orderby = Vec::new();
447    let mut desc = Vec::new();
448    for (e, a) in &mut x.orderby {
449        let e = c_value(b, e);
450        orderby.push(e);
451        desc.push(*a);
452    }
453    from = mem::replace(&mut b.from, save);
454    if index_from.is_some() {
455        from = index_from;
456    }
457    CFromExpression {
458        colnames: x.colnames,
459        assigns: x.assigns,
460        exps,
461        from,
462        wher,
463        orderby,
464        desc,
465    }
466}
467
468/// Compile WHERE clause, using table index if possible.
469pub fn c_where(
470    b: &Block,
471    table: Option<Rc<Table>>,
472    wher: &mut Option<Expr>,
473) -> (Option<CExpPtr<bool>>, Option<CTableExpression>) {
474    if let Some(we) = wher {
475        if b.kind(we) != DataKind::Bool {
476            panic!("WHERE expression must be bool")
477        }
478        if let Some(table) = table {
479            table.index_from(b, we)
480        } else {
481            (Some(c_bool(b, we)), None)
482        }
483    } else {
484        (None, None)
485    }
486}
487
488/// Compile a TableExpression to CTableExpression.
489pub fn c_te(b: &Block, te: &mut TableExpression) -> CTableExpression {
490    match te {
491        TableExpression::Values(x) => {
492            let mut cm = Vec::new();
493            for r in x {
494                let mut cr = Vec::new();
495                for e in r {
496                    let ce = c_value(b, e);
497                    cr.push(ce);
498                }
499                cm.push(cr);
500            }
501            CTableExpression::Values(cm)
502        }
503        TableExpression::Base(x) => {
504            let t = c_table(b, x);
505            CTableExpression::Base(t)
506        }
507    }
508}
509
510/// Look for named table in database.
511pub fn c_table(b: &Block, name: &ObjRef) -> Rc<Table> {
512    if let Some(t) = b.db.get_table(name) {
513        t
514    } else {
515        panic!("table {} not found", name.str())
516    }
517}
518
519/// Compile named function (if it is not already compiled ).
520pub fn c_function(db: &DB, name: &ObjRef) -> Rc<Function> {
521    if let Some(r) = db.get_function(name) {
522        let (compiled, src) = { (r.compiled.get(), r.source.clone()) };
523        if !compiled {
524            r.compiled.set(true);
525            let mut p = Parser::new(&src, db);
526            p.function_name = Some(name);
527            let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
528                p.parse_function();
529            }));
530            if let Err(x) = result {
531                r.compiled.set(false);
532                std::panic::panic_any(if let Some(sqe) = x.downcast_ref::<SqlError>() {
533                    sqe.clone()
534                } else if let Some(s) = x.downcast_ref::<&str>() {
535                    p.make_error((*s).to_string())
536                } else if let Some(s) = x.downcast_ref::<String>() {
537                    p.make_error(s.to_string())
538                } else {
539                    p.make_error("unrecognised/unexpected error".to_string())
540                });
541            }
542            *r.ilist.borrow_mut() = p.b.ilist;
543        }
544        r
545    } else {
546        panic!("function {} not found", name.str())
547    }
548}
549
550/// Lookup the column offset and DataType of a named column.
551pub fn name_to_col(b: &Block, name: &str) -> (usize, DataType) {
552    if let Some(CTableExpression::Base(t)) = &b.from {
553        let info = &t.info;
554        if let Some(num) = info.get(name) {
555            let colnum = *num;
556            if colnum == usize::MAX {
557                return (0, INT);
558            }
559            return (info.off[colnum], info.typ[colnum]);
560        }
561    }
562    panic!("Name '{}' not found", name)
563}
564
565/// Lookup the column number and DataType of a named column.
566pub fn name_to_colnum(b: &Block, name: &str) -> (usize, DataType) {
567    if let Some(CTableExpression::Base(t)) = &b.from {
568        let info = &t.info;
569        if let Some(num) = info.get(name) {
570            let colnum = *num;
571            if colnum == usize::MAX {
572                return (colnum, INT);
573            }
574            return (colnum, info.typ[colnum]);
575        }
576    }
577    panic!("Name '{}' not found", name)
578}
579
580/// Compile ExprCall to `CExpPtr<Value>`, checking parameter types.
581pub fn c_call(b: &Block, name: &ObjRef, parms: &mut Vec<Expr>) -> CExpPtr<Value> {
582    let fp = c_function(&b.db, name);
583    let mut pv = Vec::new();
584    let mut pk = Vec::new();
585    for e in parms {
586        pk.push(b.kind(e));
587        let ce = c_value(b, e);
588        pv.push(ce);
589    }
590    if fp.return_type == NONE {
591        panic!("function with no RETURN type cannot be used in expression");
592    }
593    b.check_types(&fp, &pk);
594    Box::new(cexp::Call { fp, pv })
595}
596
597/// Generate code to evaluate expression and push the value onto the stack.
598pub fn push(b: &mut Block, e: &mut Expr) -> DataKind {
599    if b.parse_only {
600        return DataKind::None;
601    }
602    let k = b.kind(e);
603    match &mut e.exp {
604        ExprIs::Const(x) => {
605            b.add(PushConst((*x).clone()));
606        }
607        ExprIs::Binary(_, _, _) => match k {
608            DataKind::Int => {
609                let ce = c_int(b, e);
610                b.add(PushInt(ce));
611            }
612            DataKind::Float => {
613                let ce = c_float(b, e);
614                b.add(PushFloat(ce));
615            }
616            DataKind::Bool => {
617                let ce = c_bool(b, e);
618                b.add(PushBool(ce));
619            }
620            _ => {
621                let ce = c_value(b, e);
622                b.add(PushValue(ce));
623            }
624        },
625        ExprIs::FuncCall(name, parms) => {
626            let rp = c_function(&b.db, name);
627            {
628                for e in parms.iter_mut() {
629                    push(b, e);
630                }
631            }
632            b.add(Call(rp));
633        }
634        ExprIs::Local(x) => {
635            b.add(PushLocal(*x));
636        }
637        _ => {
638            let ce = c_value(b, e);
639            b.add(PushValue(ce));
640        }
641    }
642    k
643}
644
645/// Compile FOR statement.
646pub fn c_for(b: &mut Block, se: FromExpression, start_id: usize, break_id: usize, for_id: usize) {
647    let mut cse = c_select(b, se);
648    let orderbylen = cse.orderby.len();
649    if orderbylen == 0 {
650        b.add(ForInit(for_id, Box::new(cse.from.unwrap())));
651        b.set_jump(start_id);
652        let info = Box::new(ForNextInfo {
653            for_id,
654            assigns: cse.assigns,
655            exps: cse.exps,
656            wher: cse.wher,
657        });
658        b.add(ForNext(break_id, info));
659    } else {
660        let assigns = mem::take(&mut cse.assigns);
661        b.add(ForSortInit(for_id, Box::new(cse)));
662        b.set_jump(start_id);
663        let info = Box::new((for_id, orderbylen, assigns));
664        b.add(ForSortNext(break_id, info));
665    }
666}