@@ -716,6 +716,150 @@ fn parse_function_now() {
716
716
assert_eq ! ( sql, ast. to_string( ) ) ;
717
717
}
718
718
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
+
719
863
fn parse_sql ( sql : & str ) -> ASTNode {
720
864
debug ! ( "sql: {}" , sql) ;
721
865
let mut parser = parser ( sql) ;
0 commit comments