|
15 | 15 | // specific language governing permissions and limitations |
16 | 16 | // under the License. |
17 | 17 |
|
18 | | -#![warn(clippy::all)] |
19 | 18 | //! Test SQL syntax, specific to [sqlparser::dialect::OracleDialect]. |
20 | 19 |
|
21 | | -extern crate core; |
22 | | - |
23 | 20 | #[cfg(test)] |
24 | 21 | use pretty_assertions::assert_eq; |
25 | 22 |
|
26 | 23 | use sqlparser::{ |
27 | | - ast::{Expr, SelectItem, Value}, |
| 24 | + ast::{BinaryOperator, Expr, Value, ValueWithSpan}, |
28 | 25 | dialect::OracleDialect, |
| 26 | + tokenizer::Span, |
29 | 27 | }; |
30 | | -#[cfg(test)] |
31 | | -use test_utils::TestedDialects; |
| 28 | +use test_utils::{expr_from_projection, number, TestedDialects}; |
32 | 29 |
|
33 | 30 | mod test_utils; |
34 | 31 |
|
| 32 | +fn oracle() -> TestedDialects { |
| 33 | + TestedDialects::new(vec![Box::new(OracleDialect)]) |
| 34 | +} |
| 35 | + |
| 36 | +/// Oracle: `||` has a lower precedence than `*` and `/` |
35 | 37 | #[test] |
36 | 38 | fn muldiv_have_higher_precedence_than_strconcat() { |
37 | | - // ~ oracle: `||` has a lower precedence than `*` and `/` |
| 39 | + // ............... A .. B ...... C .. D ........... |
38 | 40 | let sql = "SELECT 3 / 5 || 'asdf' || 7 * 9 FROM dual"; |
39 | | - let mut query = oracle_dialect().verified_query(sql); |
40 | | - nest_binary_ops(&mut query.body.as_select_mut().expect("not a SELECT").projection[0]); |
| 41 | + let select = oracle().verified_only_select(sql); |
| 42 | + assert_eq!(1, select.projection.len()); |
41 | 43 | assert_eq!( |
42 | | - &format!("{query}"), |
43 | | - "SELECT (((3 / 5) || 'asdf') || (7 * 9)) FROM dual" |
| 44 | + expr_from_projection(&select.projection[0]), |
| 45 | + // (C || D) |
| 46 | + &Expr::BinaryOp { |
| 47 | + // (A || B) |
| 48 | + left: Box::new(Expr::BinaryOp { |
| 49 | + // A |
| 50 | + left: Box::new(Expr::BinaryOp { |
| 51 | + left: Box::new(Expr::Value(number("3").into())), |
| 52 | + op: BinaryOperator::Divide, |
| 53 | + right: Box::new(Expr::Value(number("5").into())), |
| 54 | + }), |
| 55 | + op: BinaryOperator::StringConcat, |
| 56 | + right: Box::new(Expr::Value(ValueWithSpan { |
| 57 | + value: Value::SingleQuotedString("asdf".into()), |
| 58 | + span: Span::empty(), |
| 59 | + })), |
| 60 | + }), |
| 61 | + op: BinaryOperator::StringConcat, |
| 62 | + // D |
| 63 | + right: Box::new(Expr::BinaryOp { |
| 64 | + left: Box::new(Expr::Value(number("7").into())), |
| 65 | + op: BinaryOperator::Multiply, |
| 66 | + right: Box::new(Expr::Value(number("9").into())), |
| 67 | + }), |
| 68 | + } |
44 | 69 | ); |
45 | 70 | } |
46 | 71 |
|
| 72 | +/// Oracle: `+`, `-`, and `||` have the same precedence and parse from left-to-right |
47 | 73 | #[test] |
48 | 74 | fn plusminus_have_same_precedence_as_strconcat() { |
49 | | - // ~ oracle: `+`, `-`, and `||` have the same precedence and parse from left-to-right |
| 75 | + // ................ A .. B .... C .. D ............ |
50 | 76 | let sql = "SELECT 3 + 5 || '.3' || 7 - 9 FROM dual"; |
51 | | - let mut query = oracle_dialect().verified_query(sql); |
52 | | - nest_binary_ops(&mut query.body.as_select_mut().expect("not a SELECT").projection[0]); |
| 77 | + let select = oracle().verified_only_select(sql); |
| 78 | + assert_eq!(1, select.projection.len()); |
53 | 79 | assert_eq!( |
54 | | - &format!("{query}"), |
55 | | - "SELECT ((((3 + 5) || '.3') || 7) - 9) FROM dual" |
56 | | - ); |
57 | | -} |
58 | | - |
59 | | -fn oracle_dialect() -> TestedDialects { |
60 | | - TestedDialects::new(vec![Box::new(OracleDialect)]) |
61 | | -} |
62 | | - |
63 | | -/// Wraps [Expr::BinaryExpr]s in `item` with a [Expr::Nested] recursively. |
64 | | -fn nest_binary_ops(item: &mut SelectItem) { |
65 | | - // ~ idealy, we could use `VisitorMut` at this point |
66 | | - fn nest(expr: &mut Expr) { |
67 | | - // ~ ideally we could use VisitorMut here |
68 | | - if let Expr::BinaryOp { left, op: _, right } = expr { |
69 | | - nest(&mut *left); |
70 | | - nest(&mut *right); |
71 | | - let inner = std::mem::replace(expr, Expr::Value(Value::Null.into())); |
72 | | - *expr = Expr::Nested(Box::new(inner)); |
| 80 | + expr_from_projection(&select.projection[0]), |
| 81 | + // D |
| 82 | + &Expr::BinaryOp { |
| 83 | + left: Box::new(Expr::BinaryOp { |
| 84 | + // B |
| 85 | + left: Box::new(Expr::BinaryOp { |
| 86 | + // A |
| 87 | + left: Box::new(Expr::BinaryOp { |
| 88 | + left: Box::new(Expr::Value(number("3").into())), |
| 89 | + op: BinaryOperator::Plus, |
| 90 | + right: Box::new(Expr::Value(number("5").into())), |
| 91 | + }), |
| 92 | + op: BinaryOperator::StringConcat, |
| 93 | + right: Box::new(Expr::Value(ValueWithSpan { |
| 94 | + value: Value::SingleQuotedString(".3".into()), |
| 95 | + span: Span::empty(), |
| 96 | + })), |
| 97 | + }), |
| 98 | + op: BinaryOperator::StringConcat, |
| 99 | + right: Box::new(Expr::Value(number("7").into())), |
| 100 | + }), |
| 101 | + op: BinaryOperator::Minus, |
| 102 | + right: Box::new(Expr::Value(number("9").into())) |
73 | 103 | } |
74 | | - } |
75 | | - match item { |
76 | | - SelectItem::UnnamedExpr(expr) => nest(expr), |
77 | | - SelectItem::ExprWithAlias { expr, alias: _ } => nest(expr), |
78 | | - SelectItem::QualifiedWildcard(_, _) => {} |
79 | | - SelectItem::Wildcard(_) => {} |
80 | | - } |
| 104 | + ); |
81 | 105 | } |
0 commit comments