github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/norm/testdata/rules/reject_nulls (about)

     1  exec-ddl
     2  CREATE TABLE a (k INT PRIMARY KEY, i INT, f FLOAT, s STRING)
     3  ----
     4  
     5  exec-ddl
     6  CREATE TABLE xy (x INT PRIMARY KEY, y INT)
     7  ----
     8  
     9  exec-ddl
    10  CREATE TABLE uv (u INT PRIMARY KEY, v INT)
    11  ----
    12  
    13  # ----------------------------------------------------------
    14  # RejectNullsLeftJoin + RejectNullsRightJoin
    15  # ----------------------------------------------------------
    16  
    17  norm expect=RejectNullsRightJoin
    18  SELECT * FROM a FULL JOIN xy ON true WHERE a.k IS NOT NULL
    19  ----
    20  left-join (cross)
    21   ├── columns: k:1!null i:2 f:3 s:4 x:5 y:6
    22   ├── key: (1,5)
    23   ├── fd: (1)-->(2-4), (5)-->(6)
    24   ├── scan a
    25   │    ├── columns: k:1!null i:2 f:3 s:4
    26   │    ├── key: (1)
    27   │    └── fd: (1)-->(2-4)
    28   ├── scan xy
    29   │    ├── columns: x:5!null y:6
    30   │    ├── key: (5)
    31   │    └── fd: (5)-->(6)
    32   └── filters (true)
    33  
    34  norm expect=RejectNullsLeftJoin
    35  SELECT * FROM a FULL JOIN xy ON true WHERE xy.x > 5
    36  ----
    37  left-join (cross)
    38   ├── columns: k:1 i:2 f:3 s:4 x:5!null y:6
    39   ├── key: (1,5)
    40   ├── fd: (5)-->(6), (1)-->(2-4)
    41   ├── select
    42   │    ├── columns: x:5!null y:6
    43   │    ├── key: (5)
    44   │    ├── fd: (5)-->(6)
    45   │    ├── scan xy
    46   │    │    ├── columns: x:5!null y:6
    47   │    │    ├── key: (5)
    48   │    │    └── fd: (5)-->(6)
    49   │    └── filters
    50   │         └── x:5 > 5 [outer=(5), constraints=(/5: [/6 - ]; tight)]
    51   ├── scan a
    52   │    ├── columns: k:1!null i:2 f:3 s:4
    53   │    ├── key: (1)
    54   │    └── fd: (1)-->(2-4)
    55   └── filters (true)
    56  
    57  # Inner-join operator.
    58  norm expect=RejectNullsLeftJoin
    59  SELECT *
    60  FROM (SELECT * FROM a LEFT JOIN uv ON True) AS l
    61  INNER JOIN (SELECT * FROM a LEFT JOIN uv ON True) AS r
    62  ON l.u=1 AND r.v>2
    63  ----
    64  inner-join (cross)
    65   ├── columns: k:1!null i:2 f:3 s:4 u:5!null v:6 k:7!null i:8 f:9 s:10 u:11!null v:12!null
    66   ├── key: (1,7,11)
    67   ├── fd: ()-->(5,6), (1)-->(2-4), (7)-->(8-10), (11)-->(12)
    68   ├── inner-join (cross)
    69   │    ├── columns: k:1!null i:2 f:3 s:4 u:5!null v:6
    70   │    ├── key: (1)
    71   │    ├── fd: ()-->(5,6), (1)-->(2-4)
    72   │    ├── scan a
    73   │    │    ├── columns: k:1!null i:2 f:3 s:4
    74   │    │    ├── key: (1)
    75   │    │    └── fd: (1)-->(2-4)
    76   │    ├── select
    77   │    │    ├── columns: u:5!null v:6
    78   │    │    ├── cardinality: [0 - 1]
    79   │    │    ├── key: ()
    80   │    │    ├── fd: ()-->(5,6)
    81   │    │    ├── scan uv
    82   │    │    │    ├── columns: u:5!null v:6
    83   │    │    │    ├── key: (5)
    84   │    │    │    └── fd: (5)-->(6)
    85   │    │    └── filters
    86   │    │         └── u:5 = 1 [outer=(5), constraints=(/5: [/1 - /1]; tight), fd=()-->(5)]
    87   │    └── filters (true)
    88   ├── inner-join (cross)
    89   │    ├── columns: k:7!null i:8 f:9 s:10 u:11!null v:12!null
    90   │    ├── key: (7,11)
    91   │    ├── fd: (7)-->(8-10), (11)-->(12)
    92   │    ├── scan a
    93   │    │    ├── columns: k:7!null i:8 f:9 s:10
    94   │    │    ├── key: (7)
    95   │    │    └── fd: (7)-->(8-10)
    96   │    ├── select
    97   │    │    ├── columns: u:11!null v:12!null
    98   │    │    ├── key: (11)
    99   │    │    ├── fd: (11)-->(12)
   100   │    │    ├── scan uv
   101   │    │    │    ├── columns: u:11!null v:12
   102   │    │    │    ├── key: (11)
   103   │    │    │    └── fd: (11)-->(12)
   104   │    │    └── filters
   105   │    │         └── v:12 > 2 [outer=(12), constraints=(/12: [/3 - ]; tight)]
   106   │    └── filters (true)
   107   └── filters (true)
   108  
   109  # Left-join operator.
   110  norm expect=RejectNullsLeftJoin
   111  SELECT * FROM a LEFT JOIN xy ON true WHERE xy.x = a.k
   112  ----
   113  inner-join (hash)
   114   ├── columns: k:1!null i:2 f:3 s:4 x:5!null y:6
   115   ├── key: (5)
   116   ├── fd: (1)-->(2-4), (5)-->(6), (1)==(5), (5)==(1)
   117   ├── scan a
   118   │    ├── columns: k:1!null i:2 f:3 s:4
   119   │    ├── key: (1)
   120   │    └── fd: (1)-->(2-4)
   121   ├── scan xy
   122   │    ├── columns: x:5!null y:6
   123   │    ├── key: (5)
   124   │    └── fd: (5)-->(6)
   125   └── filters
   126        └── x:5 = k:1 [outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
   127  
   128  # Full-join operator.
   129  norm expect=RejectNullsLeftJoin
   130  SELECT * FROM a FULL JOIN xy ON true WHERE a.k IS NOT NULL AND xy.x > 5
   131  ----
   132  inner-join (cross)
   133   ├── columns: k:1!null i:2 f:3 s:4 x:5!null y:6
   134   ├── key: (1,5)
   135   ├── fd: (5)-->(6), (1)-->(2-4)
   136   ├── select
   137   │    ├── columns: x:5!null y:6
   138   │    ├── key: (5)
   139   │    ├── fd: (5)-->(6)
   140   │    ├── scan xy
   141   │    │    ├── columns: x:5!null y:6
   142   │    │    ├── key: (5)
   143   │    │    └── fd: (5)-->(6)
   144   │    └── filters
   145   │         └── x:5 > 5 [outer=(5), constraints=(/5: [/6 - ]; tight)]
   146   ├── scan a
   147   │    ├── columns: k:1!null i:2 f:3 s:4
   148   │    ├── key: (1)
   149   │    └── fd: (1)-->(2-4)
   150   └── filters (true)
   151  
   152  # Left-join-apply operator.
   153  norm expect=RejectNullsLeftJoin
   154  SELECT * FROM a LEFT JOIN LATERAL (SELECT * FROM (VALUES (i), (i)) v(y)) ON y>10 WHERE i=y
   155  ----
   156  inner-join-apply
   157   ├── columns: k:1!null i:2!null f:3 s:4 y:5
   158   ├── fd: (1)-->(2-4), (2)==(5), (5)==(2)
   159   ├── select
   160   │    ├── columns: k:1!null i:2!null f:3 s:4
   161   │    ├── key: (1)
   162   │    ├── fd: (1)-->(2-4)
   163   │    ├── scan a
   164   │    │    ├── columns: k:1!null i:2 f:3 s:4
   165   │    │    ├── key: (1)
   166   │    │    └── fd: (1)-->(2-4)
   167   │    └── filters
   168   │         └── i:2 > 10 [outer=(2), constraints=(/2: [/11 - ]; tight)]
   169   ├── values
   170   │    ├── columns: column1:5
   171   │    ├── outer: (2)
   172   │    ├── cardinality: [2 - 2]
   173   │    ├── (i:2,)
   174   │    └── (i:2,)
   175   └── filters
   176        └── i:2 = column1:5 [outer=(2,5), constraints=(/2: (/NULL - ]; /5: (/NULL - ]), fd=(2)==(5), (5)==(2)]
   177  
   178  # Full-join operator.
   179  norm expect=RejectNullsRightJoin
   180  SELECT * FROM a FULL JOIN xy ON true WHERE i IS NOT NULL
   181  ----
   182  left-join (cross)
   183   ├── columns: k:1!null i:2!null f:3 s:4 x:5 y:6
   184   ├── key: (1,5)
   185   ├── fd: (1)-->(2-4), (5)-->(6)
   186   ├── select
   187   │    ├── columns: k:1!null i:2!null f:3 s:4
   188   │    ├── key: (1)
   189   │    ├── fd: (1)-->(2-4)
   190   │    ├── scan a
   191   │    │    ├── columns: k:1!null i:2 f:3 s:4
   192   │    │    ├── key: (1)
   193   │    │    └── fd: (1)-->(2-4)
   194   │    └── filters
   195   │         └── i:2 IS NOT NULL [outer=(2), constraints=(/2: (/NULL - ]; tight)]
   196   ├── scan xy
   197   │    ├── columns: x:5!null y:6
   198   │    ├── key: (5)
   199   │    └── fd: (5)-->(6)
   200   └── filters (true)
   201  
   202  # ----------------------------------------------------------
   203  # RejectNullsGroupBy
   204  # ----------------------------------------------------------
   205  
   206  # Single max aggregate function.
   207  norm expect=RejectNullsGroupBy
   208  SELECT max(x)
   209  FROM (SELECT k FROM a)
   210  LEFT JOIN (SELECT x FROM xy)
   211  ON True
   212  GROUP BY k
   213  HAVING max(x)=1
   214  ----
   215  project
   216   ├── columns: max:7!null
   217   ├── fd: ()-->(7)
   218   └── select
   219        ├── columns: k:1!null max:7!null
   220        ├── key: (1)
   221        ├── fd: ()-->(7)
   222        ├── group-by
   223        │    ├── columns: k:1!null max:7!null
   224        │    ├── grouping columns: k:1!null
   225        │    ├── key: (1)
   226        │    ├── fd: (1)-->(7)
   227        │    ├── inner-join (cross)
   228        │    │    ├── columns: k:1!null x:5!null
   229        │    │    ├── key: (1,5)
   230        │    │    ├── scan a
   231        │    │    │    ├── columns: k:1!null
   232        │    │    │    └── key: (1)
   233        │    │    ├── scan xy
   234        │    │    │    ├── columns: x:5!null
   235        │    │    │    └── key: (5)
   236        │    │    └── filters (true)
   237        │    └── aggregations
   238        │         └── max [as=max:7, outer=(5)]
   239        │              └── x:5
   240        └── filters
   241             └── max:7 = 1 [outer=(7), constraints=(/7: [/1 - /1]; tight), fd=()-->(7)]
   242  
   243  # Aggregate function with DISTINCT.
   244  norm expect=RejectNullsGroupBy
   245  SELECT sum(DISTINCT y)
   246  FROM (SELECT k FROM a)
   247  LEFT JOIN (SELECT y FROM xy)
   248  ON True
   249  GROUP BY k
   250  HAVING sum(DISTINCT y)=1
   251  ----
   252  project
   253   ├── columns: sum:7!null
   254   ├── fd: ()-->(7)
   255   └── select
   256        ├── columns: k:1!null sum:7!null
   257        ├── key: (1)
   258        ├── fd: ()-->(7)
   259        ├── group-by
   260        │    ├── columns: k:1!null sum:7!null
   261        │    ├── grouping columns: k:1!null
   262        │    ├── key: (1)
   263        │    ├── fd: (1)-->(7)
   264        │    ├── inner-join (cross)
   265        │    │    ├── columns: k:1!null y:6!null
   266        │    │    ├── scan a
   267        │    │    │    ├── columns: k:1!null
   268        │    │    │    └── key: (1)
   269        │    │    ├── select
   270        │    │    │    ├── columns: y:6!null
   271        │    │    │    ├── scan xy
   272        │    │    │    │    └── columns: y:6
   273        │    │    │    └── filters
   274        │    │    │         └── y:6 IS NOT NULL [outer=(6), constraints=(/6: (/NULL - ]; tight)]
   275        │    │    └── filters (true)
   276        │    └── aggregations
   277        │         └── agg-distinct [as=sum:7, outer=(6)]
   278        │              └── sum
   279        │                   └── y:6
   280        └── filters
   281             └── sum:7 = 1 [outer=(7), constraints=(/7: [/1 - /1]; tight), fd=()-->(7)]
   282  
   283  # Single max aggregate function without grouping columns.
   284  norm expect=RejectNullsGroupBy
   285  SELECT max(x)
   286  FROM (SELECT k FROM a)
   287  LEFT JOIN (SELECT x FROM xy)
   288  ON True
   289  HAVING max(x)=1
   290  ----
   291  select
   292   ├── columns: max:7!null
   293   ├── cardinality: [0 - 1]
   294   ├── key: ()
   295   ├── fd: ()-->(7)
   296   ├── scalar-group-by
   297   │    ├── columns: max:7
   298   │    ├── cardinality: [1 - 1]
   299   │    ├── key: ()
   300   │    ├── fd: ()-->(7)
   301   │    ├── inner-join (cross)
   302   │    │    ├── columns: x:5!null
   303   │    │    ├── scan a
   304   │    │    ├── scan xy
   305   │    │    │    ├── columns: x:5!null
   306   │    │    │    └── key: (5)
   307   │    │    └── filters (true)
   308   │    └── aggregations
   309   │         └── max [as=max:7, outer=(5)]
   310   │              └── x:5
   311   └── filters
   312        └── max:7 = 1 [outer=(7), constraints=(/7: [/1 - /1]; tight), fd=()-->(7)]
   313  
   314  # Multiple aggregate functions on same column.
   315  norm expect=RejectNullsGroupBy
   316  SELECT min(x), max(x)
   317  FROM a
   318  LEFT JOIN xy
   319  ON True
   320  GROUP BY k
   321  HAVING min(x)=1
   322  ----
   323  project
   324   ├── columns: min:7!null max:8!null
   325   ├── fd: ()-->(7)
   326   └── select
   327        ├── columns: k:1!null min:7!null max:8!null
   328        ├── key: (1)
   329        ├── fd: ()-->(7), (1)-->(8)
   330        ├── group-by
   331        │    ├── columns: k:1!null min:7!null max:8!null
   332        │    ├── grouping columns: k:1!null
   333        │    ├── key: (1)
   334        │    ├── fd: (1)-->(7,8)
   335        │    ├── inner-join (cross)
   336        │    │    ├── columns: k:1!null x:5!null
   337        │    │    ├── key: (1,5)
   338        │    │    ├── scan a
   339        │    │    │    ├── columns: k:1!null
   340        │    │    │    └── key: (1)
   341        │    │    ├── scan xy
   342        │    │    │    ├── columns: x:5!null
   343        │    │    │    └── key: (5)
   344        │    │    └── filters (true)
   345        │    └── aggregations
   346        │         ├── min [as=min:7, outer=(5)]
   347        │         │    └── x:5
   348        │         └── max [as=max:8, outer=(5)]
   349        │              └── x:5
   350        └── filters
   351             └── min:7 = 1 [outer=(7), constraints=(/7: [/1 - /1]; tight), fd=()-->(7)]
   352  
   353  # Multiple aggregate functions on same column, some with DISTINCT.
   354  norm expect=RejectNullsGroupBy
   355  SELECT sum(DISTINCT y), max(y)
   356  FROM a
   357  LEFT JOIN xy
   358  ON True
   359  GROUP BY k
   360  HAVING max(y)=1
   361  ----
   362  project
   363   ├── columns: sum:7!null max:8!null
   364   ├── fd: ()-->(8)
   365   └── select
   366        ├── columns: k:1!null sum:7!null max:8!null
   367        ├── key: (1)
   368        ├── fd: ()-->(8), (1)-->(7)
   369        ├── group-by
   370        │    ├── columns: k:1!null sum:7!null max:8!null
   371        │    ├── grouping columns: k:1!null
   372        │    ├── key: (1)
   373        │    ├── fd: (1)-->(7,8)
   374        │    ├── inner-join (cross)
   375        │    │    ├── columns: k:1!null y:6!null
   376        │    │    ├── scan a
   377        │    │    │    ├── columns: k:1!null
   378        │    │    │    └── key: (1)
   379        │    │    ├── select
   380        │    │    │    ├── columns: y:6!null
   381        │    │    │    ├── scan xy
   382        │    │    │    │    └── columns: y:6
   383        │    │    │    └── filters
   384        │    │    │         └── y:6 IS NOT NULL [outer=(6), constraints=(/6: (/NULL - ]; tight)]
   385        │    │    └── filters (true)
   386        │    └── aggregations
   387        │         ├── agg-distinct [as=sum:7, outer=(6)]
   388        │         │    └── sum
   389        │         │         └── y:6
   390        │         └── max [as=max:8, outer=(6)]
   391        │              └── y:6
   392        └── filters
   393             └── max:8 = 1 [outer=(8), constraints=(/8: [/1 - /1]; tight), fd=()-->(8)]
   394  
   395  
   396  # Ignore ConstAgg aggregates on other columns.
   397  exprnorm expect=RejectNullsGroupBy
   398  (Root
   399      (Select
   400          (ScalarGroupBy
   401              (LeftJoin
   402                (Scan [ (Table "xy") (Cols "x,y") ])
   403                (Scan [ (Table "uv") (Cols "u,v") ])
   404                [ ]
   405                [ ]
   406              )
   407              [
   408                  (AggregationsItem (Sum (Var "v")) (NewColumn "sum" "int"))
   409                  (AggregationsItem (ConstAgg (Var "u")) (NewColumn "const" "int"))
   410              ]
   411              [ ]
   412          )
   413          [ (Eq (Var "sum") (Const 10 "int")) ]
   414      )
   415      (Presentation "u,v")
   416      (NoOrdering)
   417  )
   418  ----
   419  select
   420   ├── columns: u:3 v:4  [hidden: sum:5!null const:6]
   421   ├── cardinality: [0 - 1]
   422   ├── key: ()
   423   ├── fd: ()-->(5,6)
   424   ├── scalar-group-by
   425   │    ├── columns: sum:5 const:6
   426   │    ├── cardinality: [1 - 1]
   427   │    ├── key: ()
   428   │    ├── fd: ()-->(5,6)
   429   │    ├── inner-join (cross)
   430   │    │    ├── columns: u:3!null v:4!null
   431   │    │    ├── fd: (3)-->(4)
   432   │    │    ├── scan xy
   433   │    │    ├── select
   434   │    │    │    ├── columns: u:3!null v:4!null
   435   │    │    │    ├── key: (3)
   436   │    │    │    ├── fd: (3)-->(4)
   437   │    │    │    ├── scan uv
   438   │    │    │    │    ├── columns: u:3!null v:4
   439   │    │    │    │    ├── key: (3)
   440   │    │    │    │    └── fd: (3)-->(4)
   441   │    │    │    └── filters
   442   │    │    │         └── v:4 IS NOT NULL [outer=(4), constraints=(/4: (/NULL - ]; tight)]
   443   │    │    └── filters (true)
   444   │    └── aggregations
   445   │         ├── sum [as=sum:5, outer=(4)]
   446   │         │    └── v:4
   447   │         └── const-agg [as=const:6, outer=(3)]
   448   │              └── u:3
   449   └── filters
   450        └── sum:5 = 10 [outer=(5), constraints=(/5: [/10 - /10]; tight), fd=()-->(5)]
   451  
   452  # Don't reject nulls when multiple columns are used.
   453  norm expect-not=RejectNullsGroupBy
   454  SELECT min(x), max(y)
   455  FROM (select k from a)
   456  LEFT JOIN (select x, y from xy)
   457  ON True
   458  GROUP BY k
   459  HAVING min(x)=1
   460  ----
   461  project
   462   ├── columns: min:7!null max:8
   463   ├── fd: ()-->(7)
   464   └── select
   465        ├── columns: k:1!null min:7!null max:8
   466        ├── key: (1)
   467        ├── fd: ()-->(7), (1)-->(8)
   468        ├── group-by
   469        │    ├── columns: k:1!null min:7 max:8
   470        │    ├── grouping columns: k:1!null
   471        │    ├── key: (1)
   472        │    ├── fd: (1)-->(7,8)
   473        │    ├── left-join (cross)
   474        │    │    ├── columns: k:1!null x:5 y:6
   475        │    │    ├── key: (1,5)
   476        │    │    ├── fd: (5)-->(6)
   477        │    │    ├── scan a
   478        │    │    │    ├── columns: k:1!null
   479        │    │    │    └── key: (1)
   480        │    │    ├── scan xy
   481        │    │    │    ├── columns: x:5!null y:6
   482        │    │    │    ├── key: (5)
   483        │    │    │    └── fd: (5)-->(6)
   484        │    │    └── filters (true)
   485        │    └── aggregations
   486        │         ├── min [as=min:7, outer=(5)]
   487        │         │    └── x:5
   488        │         └── max [as=max:8, outer=(6)]
   489        │              └── y:6
   490        └── filters
   491             └── min:7 = 1 [outer=(7), constraints=(/7: [/1 - /1]; tight), fd=()-->(7)]
   492  
   493  # Don't reject column when count function is used (it doesn't return nil when
   494  # input is empty).
   495  norm expect-not=RejectNullsGroupBy
   496  SELECT count(x)
   497  FROM (SELECT k FROM a)
   498  LEFT JOIN (SELECT x FROM xy)
   499  ON True
   500  GROUP BY k
   501  HAVING count(x)=1
   502  ----
   503  project
   504   ├── columns: count:7!null
   505   ├── fd: ()-->(7)
   506   └── select
   507        ├── columns: k:1!null count:7!null
   508        ├── key: (1)
   509        ├── fd: ()-->(7)
   510        ├── group-by
   511        │    ├── columns: k:1!null count:7!null
   512        │    ├── grouping columns: k:1!null
   513        │    ├── key: (1)
   514        │    ├── fd: (1)-->(7)
   515        │    ├── left-join (cross)
   516        │    │    ├── columns: k:1!null x:5
   517        │    │    ├── key: (1,5)
   518        │    │    ├── scan a
   519        │    │    │    ├── columns: k:1!null
   520        │    │    │    └── key: (1)
   521        │    │    ├── scan xy
   522        │    │    │    ├── columns: x:5!null
   523        │    │    │    └── key: (5)
   524        │    │    └── filters (true)
   525        │    └── aggregations
   526        │         └── count [as=count:7, outer=(5)]
   527        │              └── x:5
   528        └── filters
   529             └── count:7 = 1 [outer=(7), constraints=(/7: [/1 - /1]; tight), fd=()-->(7)]
   530  
   531  # ConstNotNullAgg rejects nulls (regression test for #28810).
   532  # TODO(andyk): Removal of filter pushdown into apply join inputs means that this
   533  # rule no longer triggers RejectNullsGroupBy. Find another way to decorrelate
   534  # this query.
   535  # opt expect=RejectNullsGroupBy
   536  norm
   537  SELECT 1 FROM a AS ref_0 LEFT JOIN a AS ref_1 ON EXISTS(SELECT 1 FROM a WHERE a.s = ref_0.s)
   538  ----
   539  project
   540   ├── columns: "?column?":17!null
   541   ├── fd: ()-->(17)
   542   ├── left-join-apply
   543   │    ├── columns: ref_0.s:4 exists:16
   544   │    ├── scan ref_0
   545   │    │    └── columns: ref_0.s:4
   546   │    ├── project
   547   │    │    ├── columns: exists:16!null
   548   │    │    ├── outer: (4)
   549   │    │    ├── group-by
   550   │    │    │    ├── columns: ref_1.k:5!null true_agg:15
   551   │    │    │    ├── grouping columns: ref_1.k:5!null
   552   │    │    │    ├── outer: (4)
   553   │    │    │    ├── key: (5)
   554   │    │    │    ├── fd: (5)-->(15)
   555   │    │    │    ├── left-join (cross)
   556   │    │    │    │    ├── columns: ref_1.k:5!null true:14
   557   │    │    │    │    ├── outer: (4)
   558   │    │    │    │    ├── scan ref_1
   559   │    │    │    │    │    ├── columns: ref_1.k:5!null
   560   │    │    │    │    │    └── key: (5)
   561   │    │    │    │    ├── project
   562   │    │    │    │    │    ├── columns: true:14!null
   563   │    │    │    │    │    ├── outer: (4)
   564   │    │    │    │    │    ├── fd: ()-->(14)
   565   │    │    │    │    │    ├── select
   566   │    │    │    │    │    │    ├── columns: a.s:12!null
   567   │    │    │    │    │    │    ├── outer: (4)
   568   │    │    │    │    │    │    ├── fd: ()-->(12)
   569   │    │    │    │    │    │    ├── scan a
   570   │    │    │    │    │    │    │    └── columns: a.s:12
   571   │    │    │    │    │    │    └── filters
   572   │    │    │    │    │    │         └── a.s:12 = ref_0.s:4 [outer=(4,12), constraints=(/4: (/NULL - ]; /12: (/NULL - ]), fd=(4)==(12), (12)==(4)]
   573   │    │    │    │    │    └── projections
   574   │    │    │    │    │         └── true [as=true:14]
   575   │    │    │    │    └── filters (true)
   576   │    │    │    └── aggregations
   577   │    │    │         └── const-not-null-agg [as=true_agg:15, outer=(14)]
   578   │    │    │              └── true:14
   579   │    │    └── projections
   580   │    │         └── true_agg:15 IS NOT NULL [as=exists:16, outer=(15)]
   581   │    └── filters
   582   │         └── exists:16 [outer=(16), constraints=(/16: [/true - /true]; tight), fd=()-->(16)]
   583   └── projections
   584        └── 1 [as="?column?":17]
   585  
   586  # Use with multi-argument aggregate function.
   587  norm expect=RejectNullsGroupBy
   588  SELECT string_agg(s, ',')
   589  FROM (SELECT x FROM xy)
   590  LEFT JOIN (SELECT k, s FROM a)
   591  ON True
   592  GROUP BY k
   593  HAVING string_agg(s, ',')='foo'
   594  ----
   595  project
   596   ├── columns: string_agg:8!null
   597   ├── fd: ()-->(8)
   598   └── select
   599        ├── columns: k:3!null string_agg:8!null
   600        ├── key: (3)
   601        ├── fd: ()-->(8)
   602        ├── group-by
   603        │    ├── columns: k:3!null string_agg:8!null
   604        │    ├── grouping columns: k:3!null
   605        │    ├── key: (3)
   606        │    ├── fd: (3)-->(8)
   607        │    ├── project
   608        │    │    ├── columns: column7:7!null k:3!null s:6!null
   609        │    │    ├── fd: ()-->(7), (3)-->(6)
   610        │    │    ├── inner-join (cross)
   611        │    │    │    ├── columns: k:3!null s:6!null
   612        │    │    │    ├── fd: (3)-->(6)
   613        │    │    │    ├── scan xy
   614        │    │    │    ├── select
   615        │    │    │    │    ├── columns: k:3!null s:6!null
   616        │    │    │    │    ├── key: (3)
   617        │    │    │    │    ├── fd: (3)-->(6)
   618        │    │    │    │    ├── scan a
   619        │    │    │    │    │    ├── columns: k:3!null s:6
   620        │    │    │    │    │    ├── key: (3)
   621        │    │    │    │    │    └── fd: (3)-->(6)
   622        │    │    │    │    └── filters
   623        │    │    │    │         └── s:6 IS NOT NULL [outer=(6), constraints=(/6: (/NULL - ]; tight)]
   624        │    │    │    └── filters (true)
   625        │    │    └── projections
   626        │    │         └── ',' [as=column7:7]
   627        │    └── aggregations
   628        │         └── string-agg [as=string_agg:8, outer=(6,7)]
   629        │              ├── s:6
   630        │              └── column7:7
   631        └── filters
   632             └── string_agg:8 = 'foo' [outer=(8), constraints=(/8: [/'foo' - /'foo']; tight), fd=()-->(8)]
   633  
   634  # Don't reject nulls when aggregate argument is a not a Project passthrough
   635  # column.
   636  norm expect-not=RejectNullsGroupBy
   637  SELECT string_agg(s || 'bar', ',')
   638  FROM (SELECT x FROM xy)
   639  LEFT JOIN (SELECT k, s FROM a)
   640  ON True
   641  GROUP BY k
   642  HAVING string_agg(s || 'bar', ',')='foo'
   643  ----
   644  project
   645   ├── columns: string_agg:9!null
   646   ├── fd: ()-->(9)
   647   └── select
   648        ├── columns: k:3 string_agg:9!null
   649        ├── key: (3)
   650        ├── fd: ()-->(9)
   651        ├── group-by
   652        │    ├── columns: k:3 string_agg:9
   653        │    ├── grouping columns: k:3
   654        │    ├── key: (3)
   655        │    ├── fd: (3)-->(9)
   656        │    ├── project
   657        │    │    ├── columns: column7:7 column8:8!null k:3
   658        │    │    ├── fd: ()-->(8), (3)-->(7)
   659        │    │    ├── left-join (cross)
   660        │    │    │    ├── columns: k:3 s:6
   661        │    │    │    ├── fd: (3)-->(6)
   662        │    │    │    ├── scan xy
   663        │    │    │    ├── scan a
   664        │    │    │    │    ├── columns: k:3!null s:6
   665        │    │    │    │    ├── key: (3)
   666        │    │    │    │    └── fd: (3)-->(6)
   667        │    │    │    └── filters (true)
   668        │    │    └── projections
   669        │    │         ├── s:6 || 'bar' [as=column7:7, outer=(6)]
   670        │    │         └── ',' [as=column8:8]
   671        │    └── aggregations
   672        │         └── string-agg [as=string_agg:9, outer=(7,8)]
   673        │              ├── column7:7
   674        │              └── column8:8
   675        └── filters
   676             └── string_agg:9 = 'foo' [outer=(9), constraints=(/9: [/'foo' - /'foo']; tight), fd=()-->(9)]
   677  
   678  # Regression test: the not-null filter can't make it all the way down to the
   679  # join that requested it, so ensure that we don't endlessly try to introduce
   680  # them.
   681  exprnorm
   682  (Select
   683      (ScalarGroupBy
   684          (InnerJoinApply
   685            (Scan [ (Table "xy") (Cols "x,y") ])
   686                (LeftJoinApply
   687                  (Scan [ (Table "uv") (Cols "u,v") ])
   688                  (Select
   689                      (Values
   690                        [ (Tuple [ (Plus (Var "x") (Var "u")) ] "tuple{int}" ) ]
   691                        [ (Cols [ (NewColumn "z" "int") ]) ]
   692                      )
   693                      [ (Eq (Var "x") (Const 3 "int")) ]
   694                  )
   695                  [ ]
   696                  [ ]
   697                )
   698            [ ]
   699            [ ]
   700          )
   701          [ (AggregationsItem (Sum (Var "z")) (NewColumn "sum" "int")) ]
   702          [ ]
   703      )
   704      [ (Eq (Var "sum") (Const 10 "int")) ]
   705  )
   706  ----
   707  select
   708   ├── columns: sum:6!null
   709   ├── cardinality: [0 - 1]
   710   ├── key: ()
   711   ├── fd: ()-->(6)
   712   ├── scalar-group-by
   713   │    ├── columns: sum:6
   714   │    ├── cardinality: [1 - 1]
   715   │    ├── key: ()
   716   │    ├── fd: ()-->(6)
   717   │    ├── inner-join-apply
   718   │    │    ├── columns: x:1!null u:3!null z:5
   719   │    │    ├── key: (1,3)
   720   │    │    ├── fd: (1,3)-->(5)
   721   │    │    ├── scan xy
   722   │    │    │    ├── columns: x:1!null
   723   │    │    │    └── key: (1)
   724   │    │    ├── left-join-apply
   725   │    │    │    ├── columns: u:3!null z:5
   726   │    │    │    ├── outer: (1)
   727   │    │    │    ├── key: (3)
   728   │    │    │    ├── fd: (3)-->(5)
   729   │    │    │    ├── scan uv
   730   │    │    │    │    ├── columns: u:3!null
   731   │    │    │    │    └── key: (3)
   732   │    │    │    ├── values
   733   │    │    │    │    ├── columns: z:5
   734   │    │    │    │    ├── outer: (1,3)
   735   │    │    │    │    ├── cardinality: [1 - 1]
   736   │    │    │    │    ├── key: ()
   737   │    │    │    │    ├── fd: ()-->(5)
   738   │    │    │    │    └── (x:1 + u:3,)
   739   │    │    │    └── filters
   740   │    │    │         └── x:1 = 3 [outer=(1), constraints=(/1: [/3 - /3]; tight), fd=()-->(1)]
   741   │    │    └── filters (true)
   742   │    └── aggregations
   743   │         └── sum [as=sum:6, outer=(5)]
   744   │              └── z:5
   745   └── filters
   746        └── sum:6 = 10 [outer=(6), constraints=(/6: [/10 - /10]; tight), fd=()-->(6)]