I am trying to parse a simple query using sqlparser crate and I got stuck on BinaryOp struct that is value of Expr enum and the struct itself contains Expr enum.
I am able to print output by matching:
sqlparser::ast::Expr::BinaryOp{left:a , op: b , right: c} => println!("{:?}",a)
But when I try to get Expr from it, it errors with following:
error[E0308]: mismatched types
--> src/main.rs:41:57
|
38 | ... BinaryOp{left:a , op: b , right: c} => match *a {
| --
| |
| this expression has type `Box<Expr>`
| help: consider dereferencing the boxed value: `**a`
...
41 | ... sqlparser::ast::Expr::CompoundIdentifier(w) => {},
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Box`, found enum `Expr`
|
= note: expected struct `Box<Expr>`
found enum `Expr`
I assume it is the problem with dereference, however I am unable to resolve it even if I added the dereference (*a).
Complete code here:
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
use sqlparser::ast::Statement::Query;
use sqlparser::ast::SetExpr;
use sqlparser::ast::Expr::BinaryOp;
fn main() {
let dialect = GenericDialect {}; // or AnsiDialect
let sql = "SELECT a,b FROM table_1 T1 left join table_2 T2 on T1.z = T2.z";
let ast = &Parser::parse_sql(&dialect, sql).unwrap()[0];
if let Query(x) = ast {
match &x.body {
SetExpr::Select(s) => {let projection = &s.projection;
let from = &s.from;
//let group = &s.group_by;
for p in projection {
if let sqlparser::ast::SelectItem::UnnamedExpr(i) = p {
match i {
sqlparser::ast::Expr::Identifier(r) => println!("{:?}", r.value),
_ => {},
};
}
}
for f in from {
//println!("{:?}",f.relation);
for j in &f.joins {
match &j.join_operator {
sqlparser::ast::JoinOperator::Inner(inj) => println!("inner join {:?}",inj),
sqlparser::ast::JoinOperator::LeftOuter(lfj) => match lfj {
sqlparser::ast::JoinConstraint::On(on) => match on {
BinaryOp{left:a , op: b , right: c} => match *a {
sqlparser::ast::Expr::CompoundIdentifier(w) => {},
_ => {}
},
_ => {}
},
_ => {}
},
_ => {}
}
}
}
},
_ => {}
}
}
}
How it should be done to get the boxed value from BinaryOp struct?
Thank you.
The variable a
has type &Box<Expr>
, so when you dereference it, *a
, it only removes the reference leaving just Box<Expr>
. You unfortunately cannot do pattern matching on values in a Box
(see How to pattern match a Box to get a struct's attribute?), so you have to dereference it again to get an Expr
:
match **a {
However, then the match arm will try to move the variable w
out of **a
, which is not allowed since it is behind a shared reference.
You can either avoid moving entirely by referencing the Expr
via &**a
or by binding to ref w
instead of just w
. If this starts looking like too much symbol soup for you, another option is to use a.as_ref()
(via the AsRef
trait).