@@ -253,6 +253,43 @@ fn parse_create_table_partition_by_after_order_by() {
253253 "PARTITION BY col1 % 64"
254254 ) ,
255255 ) ;
256+
257+ // PARTITION BY after ORDER BY works with both ClickHouseDialect and GenericDialect
258+ clickhouse_and_generic ( )
259+ . verified_stmt ( "CREATE TABLE t (a INT) ENGINE = MergeTree ORDER BY a PARTITION BY a" ) ;
260+
261+ // Arithmetic expression in PARTITION BY (roundtrip)
262+ clickhouse_and_generic ( )
263+ . verified_stmt ( "CREATE TABLE t (a INT) ENGINE = MergeTree ORDER BY a PARTITION BY a % 64" ) ;
264+
265+ // AST: partition_by is populated with the correct expression
266+ match clickhouse_and_generic ( )
267+ . verified_stmt ( "CREATE TABLE t (a INT) ENGINE = MergeTree ORDER BY a PARTITION BY a % 64" )
268+ {
269+ Statement :: CreateTable ( CreateTable { partition_by, .. } ) => {
270+ assert_eq ! (
271+ partition_by,
272+ Some ( Box :: new( BinaryOp {
273+ left: Box :: new( Identifier ( Ident :: new( "a" ) ) ) ,
274+ op: BinaryOperator :: Modulo ,
275+ right: Box :: new( Expr :: Value (
276+ Value :: Number ( "64" . parse( ) . unwrap( ) , false ) . with_empty_span( ) ,
277+ ) ) ,
278+ } ) )
279+ ) ;
280+ }
281+ _ => unreachable ! ( ) ,
282+ }
283+
284+ // Function call expression in PARTITION BY (ClickHouse-specific function)
285+ clickhouse ( ) . verified_stmt (
286+ "CREATE TABLE t (d DATE) ENGINE = MergeTree ORDER BY d PARTITION BY toYYYYMM(d)" ,
287+ ) ;
288+
289+ // Negative: PARTITION BY with no expression should fail
290+ clickhouse_and_generic ( )
291+ . parse_sql_statements ( "CREATE TABLE t (a INT) ENGINE = MergeTree ORDER BY a PARTITION BY" )
292+ . expect_err ( "PARTITION BY with no expression should fail" ) ;
256293}
257294
258295#[ test]
@@ -1751,6 +1788,63 @@ fn test_parse_not_null_in_column_options() {
17511788 ) ;
17521789}
17531790
1791+ #[ test]
1792+ fn parse_array_join ( ) {
1793+ // ARRAY JOIN works with both ClickHouseDialect and GenericDialect (roundtrip)
1794+ clickhouse_and_generic ( ) . verified_stmt ( "SELECT x FROM t ARRAY JOIN arr AS x" ) ;
1795+
1796+ // AST: join_operator is the unit variant ArrayJoin (no constraint)
1797+ match clickhouse_and_generic ( ) . verified_stmt ( "SELECT x FROM t ARRAY JOIN arr AS x" ) {
1798+ Statement :: Query ( query) => {
1799+ let select = query. body . as_select ( ) . unwrap ( ) ;
1800+ let join = & select. from [ 0 ] . joins [ 0 ] ;
1801+ assert_eq ! ( join. join_operator, JoinOperator :: ArrayJoin ) ;
1802+ }
1803+ _ => unreachable ! ( ) ,
1804+ }
1805+
1806+ // Combined: regular JOIN followed by ARRAY JOIN
1807+ clickhouse_and_generic ( )
1808+ . verified_stmt ( "SELECT x FROM t JOIN u ON t.id = u.id ARRAY JOIN arr AS x" ) ;
1809+
1810+ // Negative: ARRAY JOIN with no table expression should fail
1811+ clickhouse_and_generic ( )
1812+ . parse_sql_statements ( "SELECT x FROM t ARRAY JOIN" )
1813+ . expect_err ( "ARRAY JOIN requires a table expression" ) ;
1814+ }
1815+
1816+ #[ test]
1817+ fn parse_left_array_join ( ) {
1818+ // LEFT ARRAY JOIN preserves rows with empty/null arrays (roundtrip)
1819+ clickhouse_and_generic ( ) . verified_stmt ( "SELECT x FROM t LEFT ARRAY JOIN arr AS x" ) ;
1820+
1821+ // AST: join_operator is LeftArrayJoin
1822+ match clickhouse_and_generic ( ) . verified_stmt ( "SELECT x FROM t LEFT ARRAY JOIN arr AS x" ) {
1823+ Statement :: Query ( query) => {
1824+ let select = query. body . as_select ( ) . unwrap ( ) ;
1825+ let join = & select. from [ 0 ] . joins [ 0 ] ;
1826+ assert_eq ! ( join. join_operator, JoinOperator :: LeftArrayJoin ) ;
1827+ }
1828+ _ => unreachable ! ( ) ,
1829+ }
1830+ }
1831+
1832+ #[ test]
1833+ fn parse_inner_array_join ( ) {
1834+ // INNER ARRAY JOIN filters rows with empty/null arrays (roundtrip)
1835+ clickhouse_and_generic ( ) . verified_stmt ( "SELECT x FROM t INNER ARRAY JOIN arr AS x" ) ;
1836+
1837+ // AST: join_operator is InnerArrayJoin
1838+ match clickhouse_and_generic ( ) . verified_stmt ( "SELECT x FROM t INNER ARRAY JOIN arr AS x" ) {
1839+ Statement :: Query ( query) => {
1840+ let select = query. body . as_select ( ) . unwrap ( ) ;
1841+ let join = & select. from [ 0 ] . joins [ 0 ] ;
1842+ assert_eq ! ( join. join_operator, JoinOperator :: InnerArrayJoin ) ;
1843+ }
1844+ _ => unreachable ! ( ) ,
1845+ }
1846+ }
1847+
17541848fn clickhouse ( ) -> TestedDialects {
17551849 TestedDialects :: new ( vec ! [ Box :: new( ClickHouseDialect { } ) ] )
17561850}
0 commit comments