Skip to content

Commit 7202466

Browse files
committed
More tests and some small bugfixes
1 parent 7624095 commit 7202466

File tree

5 files changed

+202
-27
lines changed

5 files changed

+202
-27
lines changed

src/dialect/postgresql.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ impl Dialect for PostgreSqlDialect {
1313
CHAR, CHARACTER, VARYING, LARGE, VARCHAR, CLOB, BINARY, VARBINARY, BLOB, FLOAT, REAL,
1414
DOUBLE, PRECISION, INT, INTEGER, SMALLINT, BIGINT, NUMERIC, DECIMAL, DEC, BOOLEAN,
1515
DATE, TIME, TIMESTAMP, VALUES, DEFAULT, ZONE, REGCLASS, TEXT, BYTEA, TRUE, FALSE, COPY,
16-
STDIN, PRIMARY, KEY, UNIQUE, UUID, ADD, CONSTRAINT, FOREIGN, REFERENCES,
17-
CASE, WHEN, THEN, ELSE, END,
16+
STDIN, PRIMARY, KEY, UNIQUE, UUID, ADD, CONSTRAINT, FOREIGN, REFERENCES, CASE, WHEN,
17+
THEN, ELSE, END, JOIN, LEFT, RIGHT, FULL, CROSS, OUTER, INNER, NATURAL, ON, USING,
1818
];
1919
}
2020

src/sqlast/mod.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -431,34 +431,34 @@ impl ToString for Join {
431431
}
432432
fn suffix(constraint: &JoinConstraint) -> String {
433433
match constraint {
434-
JoinConstraint::On(expr) => format!(" ON({})", expr.to_string()),
435-
JoinConstraint::Using(attrs) => format!(" USING({})", attrs.join(", ")),
434+
JoinConstraint::On(expr) => format!("ON {}", expr.to_string()),
435+
JoinConstraint::Using(attrs) => format!("USING({})", attrs.join(", ")),
436436
_ => "".to_string(),
437437
}
438438
}
439439
match &self.join_operator {
440440
JoinOperator::Inner(constraint) => format!(
441-
"{}INNER JOIN {}{}",
441+
" {}JOIN {} {}",
442442
prefix(constraint),
443443
self.relation.to_string(),
444-
prefix(constraint)
444+
suffix(constraint)
445445
),
446-
JoinOperator::Cross => format!("CROSS JOIN {}", self.relation.to_string()),
446+
JoinOperator::Cross => format!(" CROSS JOIN {}", self.relation.to_string()),
447447
JoinOperator::Implicit => format!(", {}", self.relation.to_string()),
448448
JoinOperator::LeftOuter(constraint) => format!(
449-
"{}LEFT OUTER JOIN {}{}",
449+
" {}LEFT JOIN {} {}",
450450
prefix(constraint),
451451
self.relation.to_string(),
452452
suffix(constraint)
453453
),
454454
JoinOperator::RightOuter(constraint) => format!(
455-
"{}RIGHT OUTER JOIN {}{}",
455+
" {}RIGHT JOIN {} {}",
456456
prefix(constraint),
457457
self.relation.to_string(),
458458
suffix(constraint)
459459
),
460460
JoinOperator::FullOuter(constraint) => format!(
461-
"{}FULL OUTER JOIN {}{}",
461+
" {}FULL JOIN {} {}",
462462
prefix(constraint),
463463
self.relation.to_string(),
464464
suffix(constraint)

tests/sqlparser_ansi.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,18 @@ fn parse_simple_select() {
1111
let sql = String::from("SELECT id, fname, lname FROM customer WHERE id = 1");
1212
let ast = parse_sql(&sql);
1313
match ast {
14-
ASTNode::SQLSelect {
15-
projection, ..
16-
} => {
14+
ASTNode::SQLSelect { projection, .. } => {
1715
assert_eq!(3, projection.len());
1816
}
1917
_ => assert!(false),
2018
}
2119
}
2220

23-
2421
fn parse_sql(sql: &str) -> ASTNode {
2522
let dialect = AnsiSqlDialect {};
26-
let mut tokenizer = Tokenizer::new(&dialect,&sql, );
23+
let mut tokenizer = Tokenizer::new(&dialect, &sql);
2724
let tokens = tokenizer.tokenize().unwrap();
2825
let mut parser = Parser::new(tokens);
2926
let ast = parser.parse().unwrap();
3027
ast
3128
}
32-

tests/sqlparser_generic.rs

+46-11
Original file line numberDiff line numberDiff line change
@@ -529,21 +529,20 @@ fn parse_joins_on() {
529529
})),
530530
}
531531
}
532-
533532
assert_eq!(
534-
joins_from("SELECT * FROM t1 JOIN t2 ON c1 = c2"),
533+
joins_from(verified("SELECT * FROM t1 JOIN t2 ON c1 = c2")),
535534
vec![join_with_constraint("t2", JoinOperator::Inner)]
536535
);
537536
assert_eq!(
538-
joins_from("SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2"),
537+
joins_from(verified("SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2")),
539538
vec![join_with_constraint("t2", JoinOperator::LeftOuter)]
540539
);
541540
assert_eq!(
542-
joins_from("SELECT * FROM t1 RIGHT JOIN t2 ON c1 = c2"),
541+
joins_from(verified("SELECT * FROM t1 RIGHT JOIN t2 ON c1 = c2")),
543542
vec![join_with_constraint("t2", JoinOperator::RightOuter)]
544543
);
545544
assert_eq!(
546-
joins_from("SELECT * FROM t1 FULL OUTER JOIN t2 ON c1 = c2"),
545+
joins_from(verified("SELECT * FROM t1 FULL JOIN t2 ON c1 = c2")),
547546
vec![join_with_constraint("t2", JoinOperator::FullOuter)]
548547
);
549548
}
@@ -561,25 +560,61 @@ fn parse_joins_using() {
561560
}
562561

563562
assert_eq!(
564-
joins_from("SELECT * FROM t1 JOIN t2 USING(c1)"),
563+
joins_from(verified("SELECT * FROM t1 JOIN t2 USING(c1)")),
565564
vec![join_with_constraint("t2", JoinOperator::Inner)]
566565
);
567566
assert_eq!(
568-
joins_from("SELECT * FROM t1 LEFT JOIN t2 USING(c1)"),
567+
joins_from(verified("SELECT * FROM t1 LEFT JOIN t2 USING(c1)")),
569568
vec![join_with_constraint("t2", JoinOperator::LeftOuter)]
570569
);
571570
assert_eq!(
572-
joins_from("SELECT * FROM t1 RIGHT JOIN t2 USING(c1)"),
571+
joins_from(verified("SELECT * FROM t1 RIGHT JOIN t2 USING(c1)")),
573572
vec![join_with_constraint("t2", JoinOperator::RightOuter)]
574573
);
575574
assert_eq!(
576-
joins_from("SELECT * FROM t1 FULL OUTER JOIN t2 USING(c1)"),
575+
joins_from(verified("SELECT * FROM t1 FULL JOIN t2 USING(c1)")),
577576
vec![join_with_constraint("t2", JoinOperator::FullOuter)]
578577
);
579578
}
580579

581-
fn joins_from(sql: &str) -> Vec<Join> {
582-
match parse_sql(sql) {
580+
#[test]
581+
fn parse_complex_join() {
582+
let sql = "SELECT c1, c2 FROM t1, t4 JOIN t2 ON t2.c = t1.c LEFT JOIN t3 USING(q, c) WHERE t4.c = t1.c";
583+
assert_eq!(sql, parse_sql(sql).to_string());
584+
}
585+
586+
#[test]
587+
fn parse_join_syntax_variants() {
588+
fn parses_to(from: &str, to: &str) {
589+
assert_eq!(to, &parse_sql(from).to_string())
590+
}
591+
592+
parses_to(
593+
"SELECT c1 FROM t1 INNER JOIN t2 USING(c1)",
594+
"SELECT c1 FROM t1 JOIN t2 USING(c1)",
595+
);
596+
parses_to(
597+
"SELECT c1 FROM t1 LEFT OUTER JOIN t2 USING(c1)",
598+
"SELECT c1 FROM t1 LEFT JOIN t2 USING(c1)",
599+
);
600+
parses_to(
601+
"SELECT c1 FROM t1 RIGHT OUTER JOIN t2 USING(c1)",
602+
"SELECT c1 FROM t1 RIGHT JOIN t2 USING(c1)",
603+
);
604+
parses_to(
605+
"SELECT c1 FROM t1 FULL OUTER JOIN t2 USING(c1)",
606+
"SELECT c1 FROM t1 FULL JOIN t2 USING(c1)",
607+
);
608+
}
609+
610+
fn verified(query: &str) -> ASTNode {
611+
let ast = parse_sql(query);
612+
assert_eq!(query, &ast.to_string());
613+
ast
614+
}
615+
616+
fn joins_from(ast: ASTNode) -> Vec<Join> {
617+
match ast {
583618
ASTNode::SQLSelect { joins, .. } => joins,
584619
_ => panic!("Expected SELECT"),
585620
}

tests/sqlparser_postgres.rs

+144
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,150 @@ fn parse_function_now() {
716716
assert_eq!(sql, ast.to_string());
717717
}
718718

719+
#[test]
720+
fn parse_implicit_join() {
721+
let sql = "SELECT * FROM t1, t2";
722+
723+
match verified(sql) {
724+
ASTNode::SQLSelect { joins, .. } => {
725+
assert_eq!(joins.len(), 1);
726+
assert_eq!(
727+
joins[0],
728+
Join {
729+
relation: ASTNode::SQLIdentifier("t2".to_string()),
730+
join_operator: JoinOperator::Implicit
731+
}
732+
)
733+
}
734+
_ => assert!(false),
735+
}
736+
}
737+
738+
#[test]
739+
fn parse_cross_join() {
740+
let sql = "SELECT * FROM t1 CROSS JOIN t2";
741+
742+
match verified(sql) {
743+
ASTNode::SQLSelect { joins, .. } => {
744+
assert_eq!(joins.len(), 1);
745+
assert_eq!(
746+
joins[0],
747+
Join {
748+
relation: ASTNode::SQLIdentifier("t2".to_string()),
749+
join_operator: JoinOperator::Cross
750+
}
751+
)
752+
}
753+
_ => assert!(false),
754+
}
755+
}
756+
757+
#[test]
758+
fn parse_joins_on() {
759+
fn join_with_constraint(
760+
relation: impl Into<String>,
761+
f: impl Fn(JoinConstraint) -> JoinOperator,
762+
) -> Join {
763+
Join {
764+
relation: ASTNode::SQLIdentifier(relation.into()),
765+
join_operator: f(JoinConstraint::On(ASTNode::SQLBinaryExpr {
766+
left: Box::new(ASTNode::SQLIdentifier("c1".into())),
767+
op: SQLOperator::Eq,
768+
right: Box::new(ASTNode::SQLIdentifier("c2".into())),
769+
})),
770+
}
771+
}
772+
assert_eq!(
773+
joins_from(verified("SELECT * FROM t1 JOIN t2 ON c1 = c2")),
774+
vec![join_with_constraint("t2", JoinOperator::Inner)]
775+
);
776+
assert_eq!(
777+
joins_from(verified("SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2")),
778+
vec![join_with_constraint("t2", JoinOperator::LeftOuter)]
779+
);
780+
assert_eq!(
781+
joins_from(verified("SELECT * FROM t1 RIGHT JOIN t2 ON c1 = c2")),
782+
vec![join_with_constraint("t2", JoinOperator::RightOuter)]
783+
);
784+
assert_eq!(
785+
joins_from(verified("SELECT * FROM t1 FULL JOIN t2 ON c1 = c2")),
786+
vec![join_with_constraint("t2", JoinOperator::FullOuter)]
787+
);
788+
}
789+
790+
#[test]
791+
fn parse_joins_using() {
792+
fn join_with_constraint(
793+
relation: impl Into<String>,
794+
f: impl Fn(JoinConstraint) -> JoinOperator,
795+
) -> Join {
796+
Join {
797+
relation: ASTNode::SQLIdentifier(relation.into()),
798+
join_operator: f(JoinConstraint::Using(vec!["c1".into()])),
799+
}
800+
}
801+
802+
assert_eq!(
803+
joins_from(verified("SELECT * FROM t1 JOIN t2 USING(c1)")),
804+
vec![join_with_constraint("t2", JoinOperator::Inner)]
805+
);
806+
assert_eq!(
807+
joins_from(verified("SELECT * FROM t1 LEFT JOIN t2 USING(c1)")),
808+
vec![join_with_constraint("t2", JoinOperator::LeftOuter)]
809+
);
810+
assert_eq!(
811+
joins_from(verified("SELECT * FROM t1 RIGHT JOIN t2 USING(c1)")),
812+
vec![join_with_constraint("t2", JoinOperator::RightOuter)]
813+
);
814+
assert_eq!(
815+
joins_from(verified("SELECT * FROM t1 FULL JOIN t2 USING(c1)")),
816+
vec![join_with_constraint("t2", JoinOperator::FullOuter)]
817+
);
818+
}
819+
820+
#[test]
821+
fn parse_join_syntax_variants() {
822+
fn parses_to(from: &str, to: &str) {
823+
assert_eq!(to, &parse_sql(from).to_string())
824+
}
825+
826+
parses_to(
827+
"SELECT c1 FROM t1 INNER JOIN t2 USING(c1)",
828+
"SELECT c1 FROM t1 JOIN t2 USING(c1)",
829+
);
830+
parses_to(
831+
"SELECT c1 FROM t1 LEFT OUTER JOIN t2 USING(c1)",
832+
"SELECT c1 FROM t1 LEFT JOIN t2 USING(c1)",
833+
);
834+
parses_to(
835+
"SELECT c1 FROM t1 RIGHT OUTER JOIN t2 USING(c1)",
836+
"SELECT c1 FROM t1 RIGHT JOIN t2 USING(c1)",
837+
);
838+
parses_to(
839+
"SELECT c1 FROM t1 FULL OUTER JOIN t2 USING(c1)",
840+
"SELECT c1 FROM t1 FULL JOIN t2 USING(c1)",
841+
);
842+
}
843+
844+
#[test]
845+
fn parse_complex_join() {
846+
let sql = "SELECT c1, c2 FROM t1, t4 JOIN t2 ON t2.c = t1.c LEFT JOIN t3 USING(q, c) WHERE t4.c = t1.c";
847+
assert_eq!(sql, parse_sql(sql).to_string());
848+
}
849+
850+
fn verified(query: &str) -> ASTNode {
851+
let ast = parse_sql(query);
852+
assert_eq!(query, &ast.to_string());
853+
ast
854+
}
855+
856+
fn joins_from(ast: ASTNode) -> Vec<Join> {
857+
match ast {
858+
ASTNode::SQLSelect { joins, .. } => joins,
859+
_ => panic!("Expected SELECT"),
860+
}
861+
}
862+
719863
fn parse_sql(sql: &str) -> ASTNode {
720864
debug!("sql: {}", sql);
721865
let mut parser = parser(sql);

0 commit comments

Comments
 (0)